diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..9896c6f --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2016-node5"] +} diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..804d002 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,23 @@ +engines: + duplication: + enabled: true + config: + languages: + javascript: + mass_threshold: 40 ## default threshold + eslint: + enabled: true + channel: "eslint-3" ## required for airbnb-base config + checks: + complexity: + enabled: true + csslint: + enabled: true + +ratings: ## enables GPA rating + paths: + - "**.css" + - "**.js" + +exclude_paths: +- "tests/" diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c6c8b36 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..9650bc3 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +node_modules +interface/client/lib/signatures.js diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..cf3b408 --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,47 @@ +extends: airbnb-base + +plugins: + - import + +settings: + import/core-modules: ## don't lint for these missing packages in package.json + - electron ## 'electron' is only needed as devDependency / global installation + +rules: + # "off" or 0 - turn the rule off + # "warn" or 1 - turn the rule on as a warning (doesn’t affect exit code) + # "error" or 2 - turn the rule on as an error (exit code is 1 when triggered) + indent: + - error + - 4 ## number of spaces + no-console: off ## allowed for chrome dev-console + padded-blocks: off + arrow-body-style: off + prefer-arrow-callback: off + no-underscore-dangle: off + object-curly-spacing: off + func-names: off + global-require: off + class-methods-use-this: off + comma-dangle: + - error + - only-multiline ## no comma after last item if one line, though allow comma if multiline + import/no-extraneous-dependencies: ## checks if required modules are missing in packages.json + - error + - devDependencies: ## declares files, whose imports belong to devDependencies + - "**/tests/_base.js" + - "**/*.test.js" + - "**/gulpTasks/*.js" + +globals: # don't warn about missing declarations + i18n: true + mist: true + beforeEach: true + LocalStore: true + web3: true + Tabs: true + Tracker: true + _: true + window: true + location: true + document: true diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..1d046a3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,37 @@ +* [ ] I've asked for help in the [Mist Gitter](http://gitter.im/ethereum/mist) before filing this issue. + + + +``` +Version: `0.0.0` +OS & Version: windows/linux/osx +Node version: `geth 0.0.0` +Number of blocks synchronized: 0 +``` + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..41af470 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,9 @@ +#### What does it do? + +#### Any helpful background information? + +#### Which code should the reviewer start with? + +#### New dependencies? What are they used for? + +#### Relevant screenshots? diff --git a/.github/config.yml b/.github/config.yml new file mode 100644 index 0000000..1a85a87 --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,2 @@ +maintainers: + - ethcoreorg diff --git a/.github/move.yml b/.github/move.yml new file mode 100644 index 0000000..5e532e3 --- /dev/null +++ b/.github/move.yml @@ -0,0 +1,16 @@ +# Configuration for move-issues - https://github.com/dessant/move-issues + +# Delete the command comment. Ignored when the comment also contains other content +deleteCommand: true + +# Close the source issue after moving +closeSourceIssue: true + +# Lock the source issue after moving +lockSourceIssue: false + +# Set custom aliases for targets +aliases: + wallet: ethercore/meteor-dapp-wallet + geth: ethercore/go-ethercore + parity: paritytech/parity-ethereum diff --git a/.github/triage.yml b/.github/triage.yml new file mode 100644 index 0000000..1012c93 --- /dev/null +++ b/.github/triage.yml @@ -0,0 +1,2 @@ +initLabels: + - "Status: Triage" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec8e116 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.DS_Store +node_modules/ +packages/ +interface_build/ +interface/public/i18n/ +interface/.meteor/dev_bundle +interface/.meteor/public/ +dist_wallet/ +dist_mist/ +nodes/geth/ +config.json +mist.log +npm-debug.log +/yarn.lock diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..eaad99e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "dapp-styles"] + path = interface/public/dapp-styles + url = git://github.com/ethereum/dapp-styles.git diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..37722eb --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +7.4 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..d8d9455 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +interface/.meteor +tests/mocha-in-browser/lib diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..337354d --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +singleQuote: true \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..961cc97 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,84 @@ +language: node_js +node_js: '8' +cache: + yarn: true + directories: + - node_modules + - 'interface/.meteor' + +sudo: required + +branches: + only: + - develop + - master + +matrix: + include: + # WINDOWS cross-built from linux + - os: linux + dist: trusty + env: + - GULP_PLATFORM=win + addons: + apt: + packages: + - icnsutils + - graphicsmagick + - xz-utils + - nsis + - g++-multilib + sources: + - mono + before_install: + - sudo dpkg --add-architecture i386 && sudo add-apt-repository ppa:ubuntu-wine/ppa -y + - sudo apt-get update -q + - sudo apt-get install --no-install-recommends -y mono-devel ca-certificates-mono wine1.8 + + # LINUX + - os: linux + dist: trusty + env: + - GULP_PLATFORM=linux + addons: + apt: + packages: + - icnsutils + - graphicsmagick + - xz-utils + - gcc-multilib + - g++-multilib + + # MAC + - os: osx + osx_image: xcode8.3 # currently xcode8.1+ doesn't support electron-builder macOS code-signing (https://github.com/electron-userland/electron-builder/issues/820#issuecomment-267777060) + env: + - GULP_PLATFORM=mac + before_install: + - npm install -g yarn # macOS xcode8 image doesn't natively support yarn yet + + allow_failures: + - os: osx + + fast_finish: true + + +install: + - echo $PATH + - PATH=$PATH:$HOME/.meteor && curl -L https://raw.githubusercontent.com/arunoda/travis-ci-meteor-packages/1390e0f96162d0d70fc1e60a6b0f4f891a0e8f42/configure.sh | /bin/sh + - export PATH=$PATH:`yarn global bin` + - yarn global add gulp-cli meteor-build-client electron@1.8.4 + - yarn + +script: + # disable macOS code-signing (production certificate) + - if [[ $GULP_PLATFORM != "mac" ]]; then unset CSC_LINK CSC_KEY_PASSWORD; fi + + # build wallet + - travis_wait 60 gulp --wallet --$GULP_PLATFORM + + # debug purposes - see what builds were successfully created + - ls -la ~/build/ethercore/desktop-wallet/dist_wallet/release + +after_success: + - gulp upload-queue --wallet --$GULP_PLATFORM diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..f5c89fc --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +The Mist Authors + +Alexander Van de Sande +Bas van Kervel +Fabian Vogelsteller \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e37b2a9 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,80 @@ +# Code of Conduct + +## 1. Purpose + +A primary goal of Mist project is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof). + +This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior. + +We invite all those who participate in Mist project to help us create safe and positive experiences for everyone. + +## 2. Open Source Citizenship + +A supplemental goal of this Code of Conduct is to increase open source citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community. + +Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society. + +If you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know. + +## 3. Expected Behavior + +The following behaviors are expected and requested of all community members: + +* Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community. +* Exercise consideration and respect in your speech and actions. +* Attempt collaboration before conflict. +* Refrain from demeaning, discriminatory, or harassing behavior and speech. +* Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential. +* Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations. + +## 4. Unacceptable Behavior + +The following behaviors are considered harassment and are unacceptable within our community: + +* Violence, threats of violence or violent language directed against another person. +* Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language. +* Posting or displaying sexually explicit or violent material. +* Posting or threatening to post other people’s personally identifying information ("doxing"). +* Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability. +* Inappropriate photography or recording. +* Inappropriate physical contact. You should have someone’s consent before touching them. +* Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances. +* Deliberate intimidation, stalking or following (online or in person). +* Advocating for, or encouraging, any of the above behavior. +* Sustained disruption of community events, including talks and presentations. + +## 5. Consequences of Unacceptable Behavior + +Unacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated. + +Anyone asked to stop unacceptable behavior is expected to comply immediately. + +If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event). + +## 6. Reporting Guidelines + +If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible. info@ethercore.org. + +Additionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress. + +## 7. Addressing Grievances + +If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify the Mist team with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies. + +## 8. Scope + +We expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venues–online and in-person–as well as in all one-on-one communications pertaining to community business. + +This code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members. + +## 9. Contact info + +info@ethercore.org + +## 10. License and attribution + +This Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/). + +Portions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy). + +Retrieved on November 22, 2016 from [http://citizencodeofconduct.org/](http://citizencodeofconduct.org/) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2ba3329 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# How to Contribute + +## Issues / Bug reports + +**Prior to submitting, please search -and read- _both_ open and closed issues -as _it_ may already exist.** + +To help improve Mist (_Ethereum Wallet_), please include the following: + +* What do you run? (_Binary version from [releases](https://github.com/ethereum/mist/releases) or a development version from the [commandline](https://github.com/ethereum/mist#run-mist)_) +* Which version do you use? (_Check the `VERSION` file in the Mist folder_) +* What OS you're on? + +If applicable: + +* Log file (Linux: `~/.config/Mist/logs/all.log`, Windows: `%APPDATA%/Roaming/Mist/logs/all.log`, MacOSX: `~/Library/Application Support/Mist/logs/all.log`) +* Screenshot (for GUI related issues) + +## Pull Requests + +If you want to make a PR please make sure you add a understandable description of what it is you're adding/changing/fixing. + +For formatting we use 2 _spaces_ as indentation. + +If you add any modules or files, please give them a module description and or a class description: + +``` +/** +The IPC provider backend filter and tunnel all incoming request to the IPC geth bridge. + +@module ipcProviderBackend +*/ + +/** +Mist API + +Provides an API for all dapps, which specifically targets features from the Mist browser + +@class mist +@constructor +*/ +``` diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bc08fe2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,619 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. diff --git a/MISTAPI.md b/MISTAPI.md new file mode 100644 index 0000000..695417c --- /dev/null +++ b/MISTAPI.md @@ -0,0 +1,224 @@ +# Mist API + +Mist provides an API for dapp developers to use special features only available in Mist. + +## Note for dapp developers + +To make your dapp compatible with other browsers, it is recommended that you check the `mist` object before you use it: + +```js +if(typeof mist !== 'undefined') { + ... +} +``` + +You have three different possibilities to use `web3`: + +```js +// 1. simply use it: web3 comes already defined +web3; + +// 2. optionally use web3 from Mist or load if outside of Mist +if (typeof web3 === 'undefined') + web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); + +// 3. always use web3 provided by the dapp ("Web3" won't be supplied by Mist), but the provider from Mist +if (typeof web3 !== 'undefined') web3 = new Web3(web3.currentProvider); +else web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); +``` + +## API + +* [mist.platform](#mistplatform) +* [mist.requestAccount](#mistrequestaccountcallback)(callback) +* [mist.menu](#mistmenu) +* [mist.menu.add](#mistmenuaddid-options-callback)([id,] options, callback) +* [mist.menu.clear](#mistmenuclear)() +* [mist.menu.remove](#mistmenuremoveid)(id) +* [mist.menu.select](#mistmenuselectid)(text) +* [mist.menu.setBadge](#mistmenusetbadgetext)(text) +* [mist.menu.update](#mistmenuupdateid--options--callback)(id [, options][, callback]) +* [mist.sounds](#mistsounds) +* [mist.sounds.bip](#mistsoundsbip)() +* [mist.sounds.bloop](#mistsoundsbloop)() +* [mist.sounds.invite](#mistsoundsinvite)() + +### mist.platform + +Returns the current platform, mist is running on: + +* `darwin` (Mac OSX) +* `win32` (Windows) +* `linux` (Linux) + +--- + +### mist.requestAccount(callback) + +Asks the user to provide, or create a new account. + +#### Parameters + +1. `Function` The callback to be called with the new address as the second parameter. + +#### Example + +```js +mist.requestAccount(function(e, address) { + console.log('Added new account', address); +}); +``` + +--- + +### mist.menu + +Provides functionality to control the sub menu of your dapp, when its added to the sidebar. + +--- + +### mist.menu.add([id,] options, callback) + +Adds/Updates a sub menu entry, which is placed below you dapp button in the sidebar. + +#### Parameters + +1. `String` **optional** and id string to identify your sub menu entry when updating. +2. `Object` The menu options: + * `name` (`String`): The name of the sub menu button. + * `badge` (`String|null`) **optional**: The badge text for the sub menu button, e.g. `50`. + * `position` (`Number`) **optional**: The position of the submenu button, `1` is on the top. + * `selected` (`Boolean`) **optional**: Whether or not this sub menu entry is currently selected. +3. `Function` **optional**: The callback to be called when the sub menu entry is clicked. + +#### Minimal example + +```js +mist.menu.add({ name: 'My account' }); +``` + +#### Full example + +```js +mist.menu.add( + 'tkrzU', + { + name: 'My Meny Entry', + badge: 50, + position: 1, + selected: true + }, + function() { + // Redirect + window.location = 'http://domain.com/send'; + // Using history pushstate + history.pushState(null, null, '/my-entry'); + // In Meteor iron:router + Router.go('/send'); + } +); +``` + +--- + +### mist.menu.clear() + +Removes all sub menu entries. You can use this when you reload your app, +to clear up incorrect menu entries, which might have been lost since the last session. + +#### Parameters + +None + +--- + +### mist.menu.remove(id) + +Removes a sub menu entry. + +#### Parameters + +1. `String` and id string to identify your sub menu. + +--- + +### mist.menu.select(id) + +Selects the respective sub menu entry. + +#### Parameters + +1. `String` the sub menu entry identifier. + +--- + +### mist.menu.setBadge(text) + +Sets the main badge of your dapp, right below your dapps menu button. + +#### Parameters + +1. `String` the string used as the badge text. + +--- + +### mist.menu.update(id, [, options][, callback]) + +Works like `mist.menu.add()`, but only the `id` parameter is required. + +#### Parameters + +1. `String` and id string to identify your sub menu entry. +2. `Object` The menu options: + * `name` (`String`): (optional) The name of the sub menu button. + * `badge` (`String|null`): (optional) The badge text for the sub menu button, e.g. `50`. + * `position` (`Number`): (optional) The position of the submenu button, `1` is on the top. + * `selected` (`Boolean`): (optional) Whether or not this sub menu entry is currently selected. +3. `Function` (optional) The callback to be called when the sub menu entry is clicked. + +#### Example + +```js +mist.menu.update('tkrzU', { + badge: 50, + position: 2 +}); +``` + +--- + +### mist.sounds + +Provides a list of sounds. + +--- + +### mist.sounds.bip() + +Makes a bip sound. + +#### Parameters + +None + +--- + +### mist.sounds.bloop() + +Makes a bloop sound. + +#### Parameters + +None + +--- + +### mist.sounds.invite() + +Makes an invite sound. + +#### Parameters + +None + +--- diff --git a/README.md b/README.md new file mode 100644 index 0000000..a2b3384 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# EtherCore Desktop Wallet + +[![Github All Releases](https://img.shields.io/github/downloads/ethercore/desktop-wallet/total.svg)]() + +The EtherCore Desktop Wallet is the tool of choice to store and send EtherCore coins. diff --git a/Wallet-README.txt b/Wallet-README.txt new file mode 100644 index 0000000..941c5ef --- /dev/null +++ b/Wallet-README.txt @@ -0,0 +1,60 @@ +EtherCore Wallet + +The EtherCore wallet, which allows you to create simple and multisig wallets to manage your EtherCore. + +The wallet contains its own node, but can also use an already running one, if the IPC path of that node is the standard path. +(See below) + +## Running on a testnet + +When you start the wallet on a testnet (e.g. different `--datadir`) you need to make sure to set the `--ipcpath` back to the original one. + +On OSX its `~/Library/EtherCore/geth.ipc` on linux `~/.ethercore/geth.ipc` and on windows it uses a named pipe, which doesn't need to be renamed. + +Example: + + $ geth --datadir /my/chain/ --networkid 23 --ipcpath ~/Library/Ethereum/geth.ipc + +### Original contract + +Once you start the app while running a testnet, the wallet need to deploy an original contract, +which will be used by the wallet contracts you create. + +The point of the original wallet is that wallet contract creation is cheaper, +as not the full code has to be deployed for every wallet. + +You need to make sure that the account displayed for the original wallet creation is unlocked and has at least 1 ether. + +## Paths + +The paths which store your wallets database and node are different: + +The wallet (Mist) stores its data at: + +* Mac: ~/Library/Application Support/EtherCore +* Windows: %APPDATA%\Roaming\EtherCore +* Linux: ~/.config/EtherCore + +The nodes data is stored at: + +* Mac: ~/Library/EtherCore +* Windows: %APPDATA%\Roaming\EtherCore +* Linux: ~/.ethercore + +## Issues + +If you find issues or have suggestion, please report them at +https://github.com/ethercore/meteor-dapp-wallet/issues + +## Repository + +The wallet code can be found at +https://github.com/ethercore/meteor-dapp-wallet + +And the binary application code, which wraps the wallet app can be found at +https://github.com/ethercore/desktop-wallet/tree/wallet + +## Bundling the wallet + +To bundle the binaries yourself follow the instructions on the mist#wallet readme +https://github.com/ethercore/desktop-wallet/tree/wallet#deployment diff --git a/clientBinaries.json b/clientBinaries.json new file mode 100644 index 0000000..b5e9c5c --- /dev/null +++ b/clientBinaries.json @@ -0,0 +1,75 @@ +{ + "clients": { + "Geth": { + "version": "1.9.9", + "platforms": { + "mac": { + "x64": { + "download": { + "url": "https://github.com/ethercore/go-ethercore/releases/download/v1.9.9/ethercore-geth-linux-v1.9.9.tar.gz", + "type": "tar", + "md5": "b164ca5753608d8e3686d2ca15f21656", + "bin": "build/bin/geth" + }, + "bin": "geth", + "commands": { + "sanity": { + "args": [ + "version" + ], + "output": [ + "Geth-EtherCore", + "1.9.9" + ] + } + } + } + }, + "linux": { + "x64": { + "download": { + "url": "https://github.com/ethercore/go-ethercore/releases/download/v1.9.9/ethercore-geth-osx-v1.9.9.tar.gz", + "type": "tar", + "md5": "ceba564fd2fb4a9271f7577f73425efd", + "bin": "build/bin/geth" + }, + "bin": "geth", + "commands": { + "sanity": { + "args": [ + "version" + ], + "output": [ + "Geth-EtherCore", + "1.9.9" + ] + } + } + } + }, + "win": { + "x64": { + "download": { + "url": "https://github.com/ethercore/go-ethercore/releases/download/v1.9.9/mist-win-geth.zip", + "type": "zip", + "md5": "bdd338b990c53cccb9885c0e62fde6c6", + "bin": "build\\bin\\geth.exe" + }, + "bin": "geth.exe", + "commands": { + "sanity": { + "args": [ + "version" + ], + "output": [ + "Geth-EtherCore", + "1.9.9" + ] + } + } + } + } + } + } + } +} diff --git a/customProtocols.js b/customProtocols.js new file mode 100644 index 0000000..5416a92 --- /dev/null +++ b/customProtocols.js @@ -0,0 +1,45 @@ +const { protocol } = require('electron'); + +protocol.registerHttpProtocol( + 'mist', + (request, callback) => { + // callback({mimeType: 'text/html', data: new Buffer('
Response
')}); + + console.log( + request.url.indexOf('mist://interface') !== -1 + ? global.interfaceAppUrl + request.url.replace('mist://interface', '') + : '' + ); + + const call = { + url: + request.url.indexOf('mist://interface') !== -1 + ? global.interfaceAppUrl + request.url.replace('mist://interface', '') + : '', // 'http://localhost:3050/' + request.url.replace('mist://',''), + method: request.method, + referrer: request.referrer + }; + + console.log(call); + // console.log(call); + + callback(call); + }, + error => { + if (error) { + console.error('Failed to register protocol'); + } + } +); + +// protocol.registerProtocol('eth', function(request) { +// var url = request.url.substr(7) +// return new protocol.RequestStringJob({data: 'Hello'}); +// }); + +// protocol.registerProtocol('bzz', function(request) { +// var url = request.url.substr(7) +// return new protocol.RequestStringJob({data: 'Hello'}); +// }); + +// protocol.registerStandardSchemes(['mist','eth', 'bzz']); //'eth', 'bzz' diff --git a/errorPages/400.html b/errorPages/400.html new file mode 100644 index 0000000..e4ceb70 --- /dev/null +++ b/errorPages/400.html @@ -0,0 +1,19 @@ + + + Error 400 + + + +
+ This URL is not allowed. + + \ No newline at end of file diff --git a/errorPages/404.html b/errorPages/404.html new file mode 100644 index 0000000..c0eafb9 --- /dev/null +++ b/errorPages/404.html @@ -0,0 +1,19 @@ + + + Error 404 + + + + ﴾๏๏﴿

+ URL not found. + + \ No newline at end of file diff --git a/errorPages/500.html b/errorPages/500.html new file mode 100644 index 0000000..57aee2e --- /dev/null +++ b/errorPages/500.html @@ -0,0 +1,19 @@ + + + Error 500 + + + + (ノಠ益ಠ)ノ

+ Oops.. Something went wrong! + + \ No newline at end of file diff --git a/gulpTasks/building.js b/gulpTasks/building.js new file mode 100644 index 0000000..3adc944 --- /dev/null +++ b/gulpTasks/building.js @@ -0,0 +1,294 @@ +const _ = require('underscore'); +const builder = require('electron-builder'); +const del = require('del'); +const exec = require('child_process').exec; +const fs = require('fs'); +const gulp = require('gulp'); +const babel = require('gulp-babel'); +const options = require('../gulpfile.js').options; +const path = require('path'); +const Q = require('bluebird'); +const shell = require('shelljs'); +const version = require('../package.json').version; + +const type = options.type; +const applicationName = options.wallet ? 'EtherCore Wallet' : 'Mist'; + +gulp.task('clean-dist', cb => { + return del([`./dist_${type}`, './meteor-dapp-wallet'], cb); +}); + +gulp.task('copy-app-source-files', () => { + return gulp + .src( + [ + 'node_modules/**/*', + './clientBinaries.json', + './tests/**/*.*', + `./icons/${type}/*`, + './sounds/*', + './errorPages/*', + 'customProtocols.js', + '!node_modules/electron/', + '!node_modules/electron/**/*', + '!./tests/wallet/*', + '!./tests/mist/*', + '!./tests/unit/*' + ], + { + base: './' + } + ) + .pipe(gulp.dest(`./dist_${type}/app`)); +}); + +gulp.task('transpile-main', () => { + return gulp + .src('./main.js') + .pipe(babel({ presets: ['es2016-node5'] })) + .pipe(gulp.dest(`./dist_${type}/app`)); +}); + +gulp.task('transpile-modules', () => { + return gulp + .src('./modules/**') + .pipe(babel({ presets: ['es2016-node5'] })) + .pipe(gulp.dest(`./dist_${type}/app/modules`)); +}); + +gulp.task('copy-build-folder-files', () => { + return gulp + .src([`./icons/${type}/*`, './interface/public/images/dmg-background.jpg']) + .pipe(gulp.dest(`./dist_${type}/build`)); +}); + +gulp.task('switch-production', cb => { + fs.writeFile( + `./dist_${type}/app/config.json`, + JSON.stringify({ + production: true, + mode: type + }), + cb + ); +}); + +gulp.task('bundling-interface', cb => { + const bundle = additionalCommands => { + exec( + `cd interface \ + && meteor-build-client ${path.join( + '..', + `dist_${type}`, + 'app', + 'interface' + )} -p "" \ + ${additionalCommands}`, + (err, stdout) => { + console.log(stdout); + cb(err); + } + ); + }; + + if (type === 'wallet') { + if (options.walletSource === 'local') { + console.log('Use local wallet at ../meteor-dapp-wallet/app'); + bundle(`&& cd ../../meteor-dapp-wallet/app \ + && meteor-build-client ../../mist/dist_${type}/app/interface/wallet -p ""`); + } else { + console.log( + `Pulling https://github.com/ethercore/meteor-dapp-wallet/tree/${ + options.walletSource + } "${options.walletSource}" branch...` + ); + bundle(`&& cd ../dist_${type} \ + && git clone --depth 1 https://github.com/ethercore/meteor-dapp-wallet.git \ + && cd meteor-dapp-wallet/app \ + && meteor-build-client ../../app/interface/wallet -p "" \ + && cd ../../ \ + && rm -rf meteor-dapp-wallet`); + } + } else { + bundle(); + } +}); + +gulp.task('copy-i18n', () => { + return gulp + .src(['./interface/i18n/*.*', './interface/project-tap.i18n'], { + base: './' + }) + .pipe(gulp.dest(`./dist_${type}/app`)); +}); + +gulp.task('build-dist', cb => { + const appPackageJson = _.extend({}, require('../package.json'), { + // eslint-disable-line global-require + name: applicationName.replace(/\s/, ''), + productName: applicationName, + description: applicationName, + homepage: 'https://github.com/ethercore/desktop-wallet', + build: { + appId: `org.ethercore.${type}`, + asar: true, + directories: { + buildResources: '../build', + output: '../dist' + }, + linux: { + category: 'WebBrowser', + icon: `./app/${type}/icons`, + target: ['zip'] + }, + win: { + target: ['zip'] + }, + mac: { + category: 'public.app-category.productivity' + }, + dmg: { + background: '../build/dmg-background.jpg', + iconSize: 128, + contents: [ + { + x: 441, + y: 448, + type: 'link', + path: '/Applications' + }, + { + x: 441, + y: 142, + type: 'file' + } + ] + } + } + }); + + fs.writeFileSync( + path.join(__dirname, `../dist_${type}`, 'app', 'package.json'), + JSON.stringify(appPackageJson, null, 2), + 'utf-8' + ); + + const targets = []; + if (options.mac) targets.push(builder.Platform.MAC); + if (options.win) targets.push(builder.Platform.WINDOWS); + if (options.linux) targets.push(builder.Platform.LINUX); + + builder + .build({ + targets: builder.createTargets(targets, null, 'all'), + projectDir: path.join(__dirname, `../dist_${type}`, 'app'), + publish: 'never', + config: { + afterPack(params) { + return Q.try(() => { + shell.cp( + [ + path.join(__dirname, '..', 'LICENSE'), + path.join(__dirname, '..', 'README.md'), + path.join(__dirname, '..', 'AUTHORS') + ], + params.appOutDir + ); + }); + } + } + }) + .catch(err => { + throw new Error(err); + }) + .finally(() => { + cb(); + }); +}); + +gulp.task('release-dist', done => { + const distPath = path.join(__dirname, `../dist_${type}`, 'dist'); + const releasePath = path.join(__dirname, `../dist_${type}`, 'release'); + + shell.rm('-rf', releasePath); + shell.mkdir('-p', releasePath); + + const appNameHypen = applicationName.replace(/\s/, '-'); + const appNameNoSpace = applicationName.replace(/\s/, ''); + const versionDashed = version.replace(/\./g, '-'); + + const cp = (inputPath, outputPath) => { + console.info( + `Copying from ${path.join(distPath, inputPath)} to ${path.join( + releasePath, + outputPath + )}` + ); + shell.cp( + path.join(distPath, inputPath), + path.join(releasePath, outputPath) + ); + }; + + _.each(options.activePlatforms, platform => { + switch (platform) { // eslint-disable-line default-case + case 'win': + cp( + `${applicationName}-${version}-ia32-win.zip`, + `${appNameHypen}-win32-${versionDashed}.zip` + ); + cp( + `${applicationName}-${version}-win.zip`, + `${appNameHypen}-win64-${versionDashed}.zip` + ); + break; + case 'mac': + cp( + `${applicationName}-${version}.dmg`, + `${appNameHypen}-macosx-${versionDashed}.dmg` + ); + break; + case 'linux': + // .deb have underscore separators + cp( + `${appNameNoSpace}_${version}_i386.deb`, + `${appNameHypen}-linux32-${versionDashed}.deb` + ); + cp( + `${appNameNoSpace}_${version}_amd64.deb`, + `${appNameHypen}-linux64-${versionDashed}.deb` + ); + + // .zip have dash separators + cp( + `${appNameNoSpace}-${version}-ia32.zip`, + `${appNameHypen}-linux32-${versionDashed}.zip` + ); + cp( + `${appNameNoSpace}-${version}.zip`, + `${appNameHypen}-linux64-${versionDashed}.zip` + ); + break; + } + }); + + console.info('*** Listing release files ***'); + console.info(shell.ls('-l', releasePath).map(e => e.name)); + + done(); +}); + +gulp.task('build-nsis', done => { + if (!options.win) return done(); + + const typeString = `-DTYPE=${type}`; + const appNameString = `-DAPPNAME=${applicationName.replace(/\s/, '-')}`; + const versionParts = version.split('.'); + const versionString = `-DVERSIONMAJOR=${versionParts[0]} -DVERSIONMINOR=${ + versionParts[1] + } -DVERSIONBUILD=${versionParts[2]}`; + + const cmdString = `makensis ${versionString} ${typeString} ${appNameString} scripts/windows-installer.nsi`; + + exec(cmdString, done); +}); diff --git a/gulpTasks/maintenance.js b/gulpTasks/maintenance.js new file mode 100644 index 0000000..bc04543 --- /dev/null +++ b/gulpTasks/maintenance.js @@ -0,0 +1,224 @@ +/* eslint-disable +global-require +*/ + +const _ = require('underscore'); +const cmp = require('semver-compare'); +const compare = require('json-structure-diff').compareJSONObjects; +const fs = require('fs'); +const got = require('got'); +const gulp = require('gulp'); +const parseJson = require('xml2js').parseString; +const clientBinaries = require('../clientBinaries.json'); + +gulp.task('update-nodes', cb => { + const clientBinariesGeth = clientBinaries.clients.Geth; + const localGethVersion = clientBinariesGeth.version; + const newJson = clientBinaries; + const geth = newJson.clients.Geth; + + // Query latest geth version + got('https://api.github.com/repos/ethercore/go-ethercore/releases/latest', { + json: true + }) + .then(response => { + return response.body.tag_name; + }) + // Return tag name (e.g. 'v1.5.0') + .then(tagName => { + const latestGethVersion = tagName.match(/\d+\.\d+\.\d+/)[0]; + + // Compare to current geth version in clientBinaries.json + if (cmp(latestGethVersion, localGethVersion)) { + geth.version = latestGethVersion; + + // Query commit hash (first 8 characters) + got( + `https://api.github.com/repos/ethercore/go-ethercore/commits/${tagName}`, + { json: true } + ) + .then(response => { + return String(response.body.sha).substr(0, 8); + }) + .then(hash => { + let blobs; // azure blobs + + // Query Azure assets for md5 hashes + got( + 'https://gethstore.blob.core.windows.net/builds?restype=container&comp=list', + { xml: true } + ) + .then(response => { + parseJson(response.body, (err, data) => { + // eslint-disable-line + if (err) return cb(err); + + blobs = data.EnumerationResults.Blobs[0].Blob; + }); + + // For each platform/arch in clientBinaries.json + _.keys(geth.platforms).forEach(platform => { + _.keys(geth.platforms[platform]).forEach(arch => { + // Update URL + let url = geth.platforms[platform][arch].download.url; + url = url.replace( + /\d+\.\d+\.\d+-[a-z0-9]{8}/, + `${latestGethVersion}-${hash}` + ); + geth.platforms[platform][arch].download.url = url; + + // Update bin name (path in archive) + let bin = geth.platforms[platform][arch].download.bin; + bin = bin.replace( + /\d+\.\d+\.\d+-[a-z0-9]{8}/, + `${latestGethVersion}-${hash}` + ); + geth.platforms[platform][arch].download.bin = bin; + + // Update expected sanity-command version output + geth.platforms[platform][ + arch + ].commands.sanity.output[1] = String(latestGethVersion); + + // Update md5 checksum + blobs.forEach(blob => { + if ( + String(blob.Name) === + _.last( + geth.platforms[platform][arch].download.url.split('/') + ) + ) { + const sum = new Buffer( + blob.Properties[0]['Content-MD5'][0], + 'base64' + ); + + geth.platforms[platform][ + arch + ].download.md5 = sum.toString('hex'); + } + }); + }); + }); + }) + // Update clientBinares.json + .then(() => { + fs.writeFile( + './clientBinaries.json', + JSON.stringify(newJson, null, 4) + ); + cb(); + }); + }); + } else return cb(); // Already up-to-date + }) + .catch(cb); +}); + +gulp.task('download-signatures', cb => { + got( + 'https://www.4byte.directory/api/v1/signatures/?page_size=20000&ordering=created_at', + { + json: true + } + ) + .then(res => { + if (res.statusCode !== 200) { + throw new Error(res.statusText); + } + + const signatures = {}; + + _.each(res.body.results, e => { + signatures[e.hex_signature] = signatures[e.hex_signature] || []; + signatures[e.hex_signature].push(e.text_signature); + }); + + fs.writeFileSync( + 'interface/client/lib/signatures.js', + `window.SIGNATURES = ${JSON.stringify(signatures, null, 4)};` + ); + + cb(); + }) + .catch(cb); +}); + +gulp.task('update-i18n', cb => { + /** + * This script will update Mist's i18n files + * - adds missing english strings to all translations + * - removes obsolet keys from translations + */ + + const mistEN = require('../interface/i18n/mist.en.i18n.json'); // eslint-disable-line no-unused-vars + const appEN = require('../interface/i18n/app.en.i18n.json'); // eslint-disable-line no-unused-vars + + try { + ['mist', 'app'].forEach(mode => { + const en = { + parent: 'en', + content: eval(`${mode}EN`) // eslint-disable-line no-eval + }; + + const files = fs.readdirSync('./interface/i18n'); + + files.forEach(file => { + if ( + file.indexOf(`${mode}`) !== -1 && + file.indexOf(`${mode}.en`) === -1 + ) { + const langJson = require(`../interface/i18n/${file}`); // eslint-disable-line import/no-dynamic-require + const lang = { + parent: 'lang', + content: langJson + }; + let error; + + // remove unnecessary keys + error = compare([lang, en]); + if (error) { + error.forEach(diff => { + if (diff.typeOfComparedParent === 'undefined') { + eval( + `delete lang.content.${diff.parent.slice( + diff.parent.indexOf('.') + 1 + )}` + ); // eslint-disable-line no-eval + } + }); + } + + // add missing keys + error = compare([en, lang]); + if (error) { + error.forEach(diff => { + if ( + diff.typeOfComparedParent !== diff.typeOfParent && + diff.parent !== 'en.mist.applicationMenu.view.languages' && + diff.parent !== 'en.mist.applicationMenu.view.langCodes' + ) { + eval( + `lang.content.${diff.comparedParent.slice( + diff.comparedParent.indexOf('.') + 1 + )} = en.content.${diff.parent.slice( + diff.parent.indexOf('.') + 1 + )}` + ); // eslint-disable-line no-eval + } + }); + } + + fs.writeFileSync( + `./interface/i18n/${file}`, + JSON.stringify(lang.content, null, 4) + ); + } + }); + }); + } catch (e) { + console.log(e); + } finally { + cb(); // eslint-disable-line callback-return + } +}); diff --git a/gulpTasks/publishing.js b/gulpTasks/publishing.js new file mode 100644 index 0000000..9d2fad1 --- /dev/null +++ b/gulpTasks/publishing.js @@ -0,0 +1,146 @@ +const _ = require('underscore'); +const Q = require('bluebird'); +const fs = require('fs'); +const githubUpload = Q.promisify(require('gh-release-assets')); +const got = require('got'); +const gulp = require('gulp'); +const options = require('../gulpfile.js').options; +const path = require('path'); +const shell = require('shelljs'); +const version = require('../package.json').version; + +const checksums = []; +const type = options.type; + +gulp.task('checksums', cb => { + const releasePath = `./dist_${type}/release`; + const files = fs.readdirSync(releasePath); + + let command; + let argument = ''; + + if (process.platform === 'win32') { + command = 'certUtil -hashfile'; + argument = 'SHA256'; + } else { + command = 'shasum -a 256'; + } + + files.forEach(file => { + const sum = shell.exec(`${command} "${file}" ${argument}`, { + cwd: releasePath + }); + + if (sum.code !== 0) { + Error(`Error executing shasum: ${sum.stderr}`); + } + + // store checksums for 'upload-binaries' task + checksums.push(sum.stdout); + }); + + cb(); +}); + +gulp.task('upload-binaries', cb => { + + // personal access token (public_repo) must be set using travis' ENVs + const GITHUB_TOKEN = process.env.GITHUB_TOKEN; + + console.info('Checking Github releases...'); + + // query github releases + got( + `https://api.github.com/repos/ethercore/desktop-wallet/releases?access_token=${GITHUB_TOKEN}`, + { json: true } + ) + // filter draft with current version's tag + .then(res => { + const draft = + res.body[_.indexOf(_.pluck(res.body, 'tag_name'), `v${version}`)]; + + if (draft === undefined) + throw new Error( + `Couldn't find github release draft for v${version} release tag` + ); + + return draft; + }) + // upload binaries from release folders if in draft mode + .then(draft => { + // eslint-disable-line consistent-return + if (draft.draft === true) { + const dir = `dist_${type}/release`; + const files = fs.readdirSync(dir); + const filePaths = _.map(files, file => { + return path.join(dir, file); + }); + console.log('Upload files: ', filePaths); + // check if draft already contains target binaries + // note: github replaces spaces in filenames with dots + const existingAssets = _.intersection( + files.map(file => { + return file.replace(/\s/g, '.'); + }), + _.pluck(draft.assets, 'name') + ); + if (!_.isEmpty(existingAssets)) + throw new Error( + `Github release draft already contains assets (${existingAssets}); will not upload, please remove and trigger rebuild` + ); + + return ( + githubUpload({ + url: `https://uploads.github.com/repos/ethercore/desktop-wallet/releases/${ + draft.id + }/assets{?name}`, + token: [GITHUB_TOKEN], + assets: filePaths + }) + .then(res => { + console.log( + `Successfully uploaded ${res} to v${version} release draft.` + ); + }) + // append checksums to draft text + .then(() => { + console.info( + 'Appending checksums to release notes...', + checksums + ); + if (draft.body && checksums) { + const checksumRows = checksums + .map(e => { + const line = e.replace('\n', '').split(' '); + return `${line[1]} | \`${line[0]}\``; + }) + .join('\n'); + got.patch( + `https://api.github.com/repos/ethercore/desktop-wallet/releases/${ + draft.id + }?access_token=${GITHUB_TOKEN}`, + { + body: JSON.stringify({ + tag_name: `v${version}`, + // String manipulation to create a checksums table + body: `${ + draft.body + }\n\nFile | Checksum (SHA256)\n-- | -- \n${checksumRows}` + }) + } + ); + } + }) + .catch(err => { + console.log(err); + }) + ); + } + }) + .catch(err => { + console.log(err); + }) + .then(() => { + cb(); + }); +}); diff --git a/gulpTasks/testing.js b/gulpTasks/testing.js new file mode 100644 index 0000000..0e90de9 --- /dev/null +++ b/gulpTasks/testing.js @@ -0,0 +1,14 @@ +const gulp = require('gulp'); +const mocha = require('gulp-spawn-mocha'); +const options = require('../gulpfile.js').options; + +gulp.task('test', () => { + return gulp.src([`./tests/${options.type}/${options.test}.test.js`]).pipe( + mocha({ + timeout: 60000, + ui: 'exports', + reporter: 'spec', + compilers: ['js:babel-core/register'] + }) + ); +}); diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..0847767 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,86 @@ +/* eslint-disable +import/no-extraneous-dependencies, +strict, +prefer-spread +*/ + +const _ = require('underscore'); +const gulp = require('gulp'); +const minimist = require('minimist'); +const runSeq = require('run-sequence'); + +// available crossplatform builds +let platforms; +if (process.platform === 'darwin') { + platforms = ['mac', 'linux', 'win']; +} else if (process.platform === 'win32') { + platforms = ['win']; +} else { + platforms = ['linux', 'win']; +} + +// parse commandline arguments +const args = process.argv.slice(2); +const options = minimist(args, { + string: ['walletSource', 'test', 'skipTasks'], + boolean: _.flatten(['wallet', platforms]), + default: { + wallet: false, + walletSource: 'master', + test: 'basic', + skipTasks: '' + } +}); + +// echo version info and usage hints +console.log('Mist version:', require('./package.json').version); +console.log('Electron version:', require('electron/package.json').version); + +if (_.isEmpty(_.intersection(args, ['--wallet']))) { + console.log('Many gulp tasks can be run in wallet mode using: --wallet'); +} + +const platformFlags = platforms.map(platform => { + return `--${platform}`; +}); +if (_.isEmpty(_.intersection(args, platformFlags))) { + console.log( + `To specify a platform (default: all) use: ${platformFlags.join(' ')}` + ); + _.each(platforms, platform => { + options[platform] = true; + }); // activate all platform flags +} + +// prepare global variables (shared with other gulp task files) +options.type = options.wallet ? 'wallet' : 'mist'; +options.platforms = platforms; +options.activePlatforms = _.keys( + _.pick(_.pick(options, platforms), key => { + return key; + }) +); + +exports.options = options; + +// import gulp tasks +require('require-dir')('./gulpTasks'); + +gulp.task('upload-queue', gulp.series('checksums', 'upload-binaries')); + +const skipTasks = options.skipTasks.replace(/\s/g, '').split(','); +const tasks = [ + 'clean-dist', + 'copy-app-source-files', + 'transpile-main', + 'transpile-modules', + 'copy-build-folder-files', + 'switch-production', + 'bundling-interface', + 'copy-i18n', + 'build-dist', + 'release-dist', + 'build-nsis' +].filter(task => !skipTasks.includes(task)); + +gulp.task('default', gulp.series(tasks)); diff --git a/icons/mist/icon.icns b/icons/mist/icon.icns new file mode 100644 index 0000000..8cefa23 Binary files /dev/null and b/icons/mist/icon.icns differ diff --git a/icons/mist/icon.ico b/icons/mist/icon.ico new file mode 100644 index 0000000..fd94d76 Binary files /dev/null and b/icons/mist/icon.ico differ diff --git a/icons/mist/icon.png b/icons/mist/icon.png new file mode 100644 index 0000000..6b59c9b Binary files /dev/null and b/icons/mist/icon.png differ diff --git a/icons/mist/icon2x.png b/icons/mist/icon2x.png new file mode 100644 index 0000000..2b6247d Binary files /dev/null and b/icons/mist/icon2x.png differ diff --git a/icons/wallet/icon.icns b/icons/wallet/icon.icns new file mode 100644 index 0000000..2d32510 Binary files /dev/null and b/icons/wallet/icon.icns differ diff --git a/icons/wallet/icon.ico b/icons/wallet/icon.ico new file mode 100644 index 0000000..589707b Binary files /dev/null and b/icons/wallet/icon.ico differ diff --git a/icons/wallet/icon.png b/icons/wallet/icon.png new file mode 100644 index 0000000..5044fc5 Binary files /dev/null and b/icons/wallet/icon.png differ diff --git a/icons/wallet/icon2x.fw.png b/icons/wallet/icon2x.fw.png new file mode 100644 index 0000000..b5ae321 Binary files /dev/null and b/icons/wallet/icon2x.fw.png differ diff --git a/icons/wallet/icon2x.png b/icons/wallet/icon2x.png new file mode 100644 index 0000000..b5ae321 Binary files /dev/null and b/icons/wallet/icon2x.png differ diff --git a/interface/.eslintrc.yml b/interface/.eslintrc.yml new file mode 100644 index 0000000..f30336e --- /dev/null +++ b/interface/.eslintrc.yml @@ -0,0 +1,17 @@ +env: # don't warn about no-def meteor keywords + meteor: true + +rules: + no-undef: 0 + no-var: 0 + prefer-arrow-callback: 0 + prefer-template: 0 + no-underscore-dangle: + - error + - allow: ['_id', '_escape', '__'] + +globals: + Helpers: true + Blaze: true + EthAccounts: true + mist: true diff --git a/interface/.meteor/.finished-upgraders b/interface/.meteor/.finished-upgraders new file mode 100644 index 0000000..aa60704 --- /dev/null +++ b/interface/.meteor/.finished-upgraders @@ -0,0 +1,15 @@ +# This file contains information which helps Meteor properly upgrade your +# app when you run 'meteor update'. You should check it into version control +# with your project. + +notices-for-0.9.0 +notices-for-0.9.1 +0.9.4-platform-file +notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes +1.3.0-split-minifiers-package +1.4.0-remove-old-dev-bundle-link +1.4.1-add-shell-server-package diff --git a/interface/.meteor/.gitignore b/interface/.meteor/.gitignore new file mode 100644 index 0000000..4083037 --- /dev/null +++ b/interface/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/interface/.meteor/.id b/interface/.meteor/.id new file mode 100644 index 0000000..e201474 --- /dev/null +++ b/interface/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +1vzgwat16lvg098rknpa diff --git a/interface/.meteor/packages b/interface/.meteor/packages new file mode 100644 index 0000000..2b36f0b --- /dev/null +++ b/interface/.meteor/packages @@ -0,0 +1,46 @@ +# Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +less@2.7.8 +tap:i18n +jeeeyul:moment-with-langs +ostrio:templatehelpers +raix:handlebar-helpers +frozeman:animation-helper +frozeman:template-var +frozeman:reactive-timer +frozeman:storage +frozeman:global-notifications +reactive-var@1.0.11 +sacha:spin +chuangbo:cookie +agnito:simptip +mrt:jquery-ui-sortable +ethereum:web3 +ethereum:elements +ethereum:accounts +ethereum:blocks +ethereum:dapp-styles +meteor-base@1.0.4 +mobile-experience@1.0.4 +mongo@1.1.14 +blaze-html-templates +session@1.1.7 +jquery@1.11.10 +tracker@1.1.1 +logging@1.1.16 +reload@1.1.11 +random@1.0.10 +ejson@1.0.13 +spacebars +check@1.2.4 +standard-minifier-css@1.3.2 +standard-minifier-js@1.2.1 +tap:i18n-bundler +shell-server +ecmascript +numeral:numeral +numeral:languages diff --git a/interface/.meteor/platforms b/interface/.meteor/platforms new file mode 100644 index 0000000..8a3a35f --- /dev/null +++ b/interface/.meteor/platforms @@ -0,0 +1,2 @@ +browser +server diff --git a/interface/.meteor/release b/interface/.meteor/release new file mode 100644 index 0000000..61f6c67 --- /dev/null +++ b/interface/.meteor/release @@ -0,0 +1 @@ +METEOR@1.4.2.3 diff --git a/interface/.meteor/versions b/interface/.meteor/versions new file mode 100644 index 0000000..06f82b3 --- /dev/null +++ b/interface/.meteor/versions @@ -0,0 +1,107 @@ +3stack:bignumber@2.0.7 +agnito:simptip@0.0.1 +aldeed:simple-schema@1.5.3 +alexvandesande:identicon@2.0.2 +allow-deny@1.0.5 +amplify@1.0.0 +autoupdate@1.3.12 +babel-compiler@6.13.0 +babel-runtime@1.0.1 +base64@1.0.10 +binary-heap@1.0.10 +blaze@2.2.0 +blaze-html-templates@1.0.5 +blaze-tools@1.0.10 +boilerplate-generator@1.0.11 +caching-compiler@1.1.9 +caching-html-compiler@1.0.7 +callback-hook@1.0.10 +cfs:http-methods@0.0.32 +check@1.2.4 +chuangbo:cookie@1.1.0 +coffeescript@1.11.1_4 +cosmos:browserify@0.10.0 +ddp@1.2.5 +ddp-client@1.3.2 +ddp-common@1.2.8 +ddp-server@1.3.12 +deps@1.0.12 +diff-sequence@1.0.7 +ecmascript@0.6.1 +ecmascript-runtime@0.3.15 +ejson@1.0.13 +ethereum:accounts@0.3.12 +ethereum:blocks@0.3.2 +ethereum:dapp-styles@0.5.7 +ethereum:elements@0.7.18 +ethereum:tools@0.6.0 +ethereum:web3@0.15.3 +fastclick@1.0.13 +frozeman:animation-helper@0.2.6 +frozeman:global-notifications@0.2.1 +frozeman:persistent-minimongo@0.1.8 +frozeman:reactive-timer@0.1.7 +frozeman:storage@0.1.9 +frozeman:template-var@1.3.0 +geojson-utils@1.0.10 +hot-code-push@1.0.4 +html-tools@1.0.11 +htmljs@1.0.11 +http@1.2.10 +id-map@1.0.9 +jeeeyul:moment-with-langs@2.12.1 +jquery@1.11.10 +launch-screen@1.1.0 +less@2.7.8 +livedata@1.0.18 +localstorage@1.0.12 +logging@1.1.16 +mdg:validation-error@0.2.0 +meteor@1.6.0 +meteor-base@1.0.4 +meteorspark:util@0.2.0 +minifier-css@1.2.15 +minifier-js@1.2.15 +minimongo@1.0.19 +mobile-experience@1.0.4 +mobile-status-bar@1.0.13 +modules@0.7.7 +modules-runtime@0.7.7 +mongo@1.1.14 +mongo-id@1.0.6 +mrt:jquery-ui-sortable@1.10.3 +npm-mongo@2.2.11_2 +numeral:languages@1.5.3 +numeral:numeral@1.5.3_1 +observe-sequence@1.0.14 +ordered-dict@1.0.9 +ostrio:templatehelpers@1.1.3 +promise@0.8.8 +raix:eventemitter@0.1.3 +raix:handlebar-helpers@0.2.5 +random@1.0.10 +reactive-dict@1.1.8 +reactive-var@1.0.11 +reload@1.1.11 +retry@1.0.9 +routepolicy@1.0.12 +sacha:spin@2.3.1 +session@1.1.7 +shell-server@0.2.1 +spacebars@1.0.13 +spacebars-compiler@1.0.13 +standard-minifier-css@1.3.2 +standard-minifier-js@1.2.1 +standard-minifiers@1.0.6 +tap:i18n@1.8.2 +tap:i18n-bundler@0.3.0 +templating@1.2.15 +templating-compiler@1.2.15 +templating-runtime@1.2.15 +templating-tools@1.0.5 +tracker@1.1.1 +ui@1.0.12 +underscore@1.0.10 +url@1.0.11 +webapp@1.3.12 +webapp-hashing@1.0.9 diff --git a/interface/client/actions.js b/interface/client/actions.js new file mode 100644 index 0000000..deb5a67 --- /dev/null +++ b/interface/client/actions.js @@ -0,0 +1,15 @@ +exports.getLanguage = function getLanguage() { + return function(dispatch) { + dispatch({ type: '[CLIENT]:GET_LANGUAGE:START' }); + try { + const lang = ipc.sendSync('backendAction_getLanguage'); + TAPi18n.setLanguage(lang); + dispatch({ + type: '[CLIENT]:GET_LANGUAGE:SUCCESS', + payload: { i18n: lang } + }); + } catch (error) { + dispatch({ type: '[CLIENT]:GET_LANGUAGE:FAILURE', error }); + } + }; +}; diff --git a/interface/client/appStart.js b/interface/client/appStart.js new file mode 100644 index 0000000..f7e173a --- /dev/null +++ b/interface/client/appStart.js @@ -0,0 +1,96 @@ +const { getLanguage } = require('./actions.js'); + +/** +The init function of Mist + +@method mistInit +*/ +mistInit = function() { + console.info('Initialise Mist Interface'); + + EthBlocks.init(); + const ethBlocksInterval = setInterval(() => { + if (_.isEmpty(EthBlocks.latest)) { + EthBlocks.init(); + } else { + clearInterval(ethBlocksInterval); + } + }, 500); + + Tabs.onceSynced.then(function() { + if (location.search.indexOf('reset-tabs') >= 0) { + console.info('Resetting UI tabs'); + + Tabs.remove({}); + } + + if (!Tabs.findOne('browser')) { + console.debug('Insert tabs'); + + Tabs.insert({ + _id: 'browser', + url: 'https://ethercore.org', + redirect: 'https://ethercore.org', + position: 0 + }); + } else { + Tabs.upsert( + { _id: 'browser' }, + { + $set: { position: 0 } + } + ); + } + + // overwrite wallet on start again, but use $set to preserve account titles + Tabs.upsert( + { _id: 'wallet' }, + { + $set: { + url: 'https://ethercore.org', + redirect: 'https://ethercore.org', + position: 1, + permissions: { + admin: true + } + } + } + ); + + // on first use of Mist, show the wallet to nudge the user to create an account + if ( + !LocalStore.get('selectedTab') || + !Tabs.findOne(LocalStore.get('selectedTab')) + ) { + LocalStore.set('selectedTab', 'wallet'); + } + }); +}; + +Meteor.startup(function() { + console.info('Meteor starting up...'); + + if (!location.hash) { + // Main window + EthAccounts.init(); + mistInit(); + } + + store.dispatch(getLanguage()); + + // change moment and numeral language, when language changes + Tracker.autorun(function() { + if (_.isString(TAPi18n.getLanguage())) { + const lang = TAPi18n.getLanguage().substr(0, 2); + moment.locale(lang); + try { + numeral.language(lang); + } catch (err) { + console.warn( + `numeral.js couldn't set number formating: ${err.message}` + ); + } + EthTools.setLocale(lang); + } + }); +}); diff --git a/interface/client/collections.js b/interface/client/collections.js new file mode 100644 index 0000000..2451f6e --- /dev/null +++ b/interface/client/collections.js @@ -0,0 +1,39 @@ +/** + +@module Collections +*/ + +// BROWSER RELATED +// Contains the accounts +Tabs = new Mongo.Collection('tabs', { connection: null }); +LastVisitedPages = new Mongo.Collection('last-visted-pages', { + connection: null +}); +History = new Mongo.Collection('history', { connection: null }); + +// Sync collection from and to the backend loki.js +if (typeof window.dbSync !== 'undefined') { + Tabs = window.dbSync.frontendSyncInit(Tabs); + LastVisitedPages = window.dbSync.frontendSyncInit(LastVisitedPages); + History = window.dbSync.frontendSyncInit(History); +} + +// ETHEREUM RELATED + +// Accounts collection is add by the ethereum:accounts package + +// LastBlock collection is add by the ethereum:accounts package + +// contains blockchain meta data +// LastBlock = new Mongo.Collection('lastblock', {connection: null}); +// new PersistentMinimongo2(LastBlock, 'Mist'); +// if(!LastBlock.findOne('latest')) +// LastBlock.insert({ +// _id: 'latest', +// blockNumber: 0, +// blockHash: 0, +// gasPrice: 0, +// checkpoint: 0 +// }); + +// Blockchain = new Mongo.Collection('blockchain', {connection: null}); diff --git a/interface/client/lib/ethereum/1_web3js_init.js b/interface/client/lib/ethereum/1_web3js_init.js new file mode 100644 index 0000000..bee60f5 --- /dev/null +++ b/interface/client/lib/ethereum/1_web3js_init.js @@ -0,0 +1,10 @@ +// set providor +if (typeof web3 !== 'undefined') { + console.info('Web3 already initialized, re-using provider.'); + + web3 = new Web3(web3.currentProvider); +} else { + console.info('Web3 not yet initialized, doing so now with HttpProvider.'); + + web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); +} diff --git a/interface/client/lib/helpers/helperFunctions.js b/interface/client/lib/helpers/helperFunctions.js new file mode 100644 index 0000000..148ea74 --- /dev/null +++ b/interface/client/lib/helpers/helperFunctions.js @@ -0,0 +1,438 @@ +/** +Helper functions + +@module Helpers +**/ + +/** +The Helpers class containing helper functions + +@class Helpers +@constructor +**/ +Helpers = {}; + +/** +The preloader dirname + +@property preloaderDirname +**/ +Helpers.preloaderDirname = window.dirname + '/modules/preloader'; + +/** +Reruns functions reactively, based on an interval. Use it like so: + + Helpers.rerun['10s'].tick(); + + +@method rerun +**/ +Helpers.rerun = { + '10s': new ReactiveTimer(10), + '1s': new ReactiveTimer(1) +}; + +/** +Get the webview from either and ID, or the string "browser" + +@method getWebview +@param {String} id The Id of a tab or the string "browser" +*/ +Helpers.getWebview = function(id) { + return $('webview[data-id="' + id + '"]')[0]; +}; + +/** +Get tab by url and return the id + +@method getTabIdByUrl +@param {String} url +@return {String} id +*/ +Helpers.getTabIdByUrl = function(url, returnEmpty) { + var tabs = Tabs.find().fetch(); + url = Helpers.sanitizeUrl(url); + + var foundTab = _.find(tabs, function(tab) { + if (tab._id === 'browser' || !tab.url) { + return false; + } + var tabOrigin = new URL(tab.url).origin; + return url && new URL(url).origin.indexOf(tabOrigin) === 0; + }); + + // switch tab to browser + if (foundTab) { + foundTab = foundTab._id; + } else { + foundTab = 'browser'; + } + + return foundTab; +}; + +/** +Format Urls, e.g add a default protocol if on is missing. + +@method formatUrl +@param {String} url +**/ +Helpers.formatUrl = function(url) { + if (!url) return; + + // add http:// if no protocol is present + if (url.length === 64 && !!url.match(/^[0-9a-f]+$/)) { + // if the url looks like a hash, add bzz + url = 'bzz://' + url; + } else if (!!url.match(/^([a-z]*:\/\/)?[^/]*\.eth(\/.*)?$/i)) { + // if uses .eth as a TLD + url = 'bzz://' + url.replace(/^([a-z]*:\/\/)?/i, ''); + } else if (!!url.match(/^[^\.\/]*$/i)) { + // doesn't have a protocol nor a TLD + url = 'bzz://' + url + '.eth'; + } else if (url.indexOf('://') === -1) { + // if it doesn't have a protocol + url = 'http://' + url; + } + + return url; +}; + +/** +Sanatizes URLs to prevent phishing and XSS attacks + +@method sanitizeUrl +@param {String} url +**/ +Helpers.sanitizeUrl = function(url, returnEmptyURL) { + url = String(url); + + url = url.replace(/[\t\n\r\s]+/g, ''); + url = url.replace(/^[:\/]{1,3}/i, 'http://'); + + if (returnEmptyURL && /^(?:file|javascript|data):/i.test(url)) { + url = false; + } + + return url; +}; + +/** +Takes an URL and creates a breadcrumb out of it. + +@method generateBreadcrumb +@return Spacebars.SafeString +**/ +Helpers.generateBreadcrumb = function(url) { + var filteredUrl; + var pathname; + + filteredUrl = { + protocol: Blaze._escape(url.protocol), + host: Blaze._escape(url.host), + pathname: Blaze._escape(url.pathname), + search: Blaze._escape(url.search), + hash: Blaze._escape(url.hash) + }; + + filteredUrl.pathname += filteredUrl.search.replace(/\?/g, '/'); + filteredUrl.pathname += filteredUrl.hash.replace(/#/g, '/'); + + pathname = _.reject( + filteredUrl.pathname.replace(/\/$/g, '').split('/'), + function(el) { + return el === ''; + } + ); + + return new Spacebars.SafeString( + filteredUrl.protocol + + '//' + + _.flatten(['' + filteredUrl.host + ' ', pathname]).join( + ' ▸ ' + ) + ); +}; + +/** +Clear localStorage + +@method getLocalStorageSize +**/ +Helpers.getLocalStorageSize = function() { + var size = 0; + if (localStorage) { + _.each(Object.keys(localStorage), function(key) { + size += localStorage[key].length * 2 / 1024 / 1024; + }); + } + + return size; +}; + +/** +Makes tab with index active + +@method selecTabWithIndex +@param {Integer} index +*/ +Helpers.selectTabWithIndex = function(index) { + var tabList = Tabs.find( + {}, + { sort: { position: 1 }, fields: { _id: 1 } } + ).fetch(); + if (index < tabList.length) { + LocalStore.set('selectedTab', tabList[index]._id); + } +}; + +/** +Makes last tab active + +@method selecLastTab +*/ +Helpers.selectLastTab = function() { + var lastTab = Tabs.findOne( + {}, + { sort: { position: -1 }, fields: { _id: 1 }, limit: 1 } + ); + LocalStore.set('selectedTab', lastTab._id); +}; + +/** +Selects previous or next tab (offset +1 or -1) + +@method selectTabWithOffset +*/ +Helpers.selectTabWithOffset = function(offset) { + var tabList; + var currentTabIndex; + var newTabIndex; + + if (Math.abs(offset) !== 1) { + return; + } + tabList = _.pluck( + Tabs.find({}, { sort: { position: 1 }, fields: { _id: 1 } }).fetch(), + '_id' + ); + currentTabIndex = tabList.indexOf(LocalStore.get('selectedTab')); + + newTabIndex = (currentTabIndex + offset) % tabList.length; + if (newTabIndex < 0) { + newTabIndex = tabList.length - 1; + } + + LocalStore.set('selectedTab', tabList[newTabIndex]); +}; + +/** +Detect Network + +@method detectNetwork +**/ +Helpers.detectNetwork = function(hash) { + var network = {}; + + switch (hash) { + case '0x9bc5f1def3b96ac2b4a6d7f8a5047d6db2451328eb9469df48c06a6a4a4f3734': + console.log('Network is mainnet'); + network.type = 'mainnet'; + network.name = 'Main'; + break; + + case '0x882bef94a19a1ea0dce9cb602fec35f82164535e641e4898ddc8a0ab6ecbd2f5': + console.log('Network is Testnet'); + network.type = 'testnet'; + network.name = 'Testnet'; + break; + + default: + console.log('Network is privatenet'); + network.type = 'privatenet'; + network.name = 'Private'; + } + + return network; +}; + +/** +Displays an error as global notification + +@method displayError +@param {Object} error The error object +@param {Boolean} accounts will show the accounts errors +@return {Boolean} +**/ +// Helpers.displayError = function(error, accounts) { +// var duration = 8; + +// if(error) { + +// if(error.reason){ +// // hack to make account errors still work +// if(accounts) { +// GlobalNotification.error({ +// content: 'i18n:accounts.error.' + error.reason.toLowerCase().replace(/[ ]+/g, ''), +// duration: duration +// }); + +// } else { +// GlobalNotification.error({ +// content: 'i18n:'+ error.reason, +// duration: duration +// }); +// } +// } else if(error.message) { +// GlobalNotification.error({ +// content: error.message, +// duration: duration +// }); +// } else { +// GlobalNotification.error({ +// content: error, +// duration: duration +// }); +// } + +// return true; + +// } else +// return false; +// }; + +/** +Get form values and build a parameters object out of it. + +@method formValuesToParameters +@param {Element} elements DOM-Elements elements, selects, inputs and textareas, to get values from. Must have a name tag +@return {Object} An object with parameters to pass to the API Controller e.g.: + + { + key1: 'value1', + key2: 'value2' + } +**/ +// Helpers.formValuesToParameters = function(elements) { +// var parameters = {}; + +// $(elements).each(function(){ +// var $element = $(this), +// name = $element.attr('name'), +// value = $element.val(); + +// // add only values wich are not null or empty +// if(name && !_.isEmpty(value) && value !== 'null' && value !== 'NULL') { +// if(_.isFinite(value)) +// parameters[name] = parseInt(value); +// else if(_.isBoolean(value)) +// parameters[name] = (value === 'true' || value === 'True' || value === 'TRUE') ? true : false; +// else if($element.attr('type') === 'radio') +// parameters[name] = ($element.is(':checked')) ? true : false; +// else if($element.attr('type') === 'checkbox') +// parameters[name] = ($element.is(':checked')) ? true : false; +// else +// parameters[name] = value; +// } +// $element = null; +// }); + +// return parameters; +// }; + +/** +Reactive wrapper for the moment package. + +@method moment +@param {String} time a date object passed to moment function. +@return {Object} the moment js package +**/ +// Helpers.moment = function(time){ + +// // react to language changes as well +// TAPi18n.getLanguage(); + +// if(_.isFinite(time) && moment.unix(time).isValid()) +// return moment.unix(time); +// else +// return moment(time); + +// }; + +/** +Formats a timestamp to any format given. + + Helpers.formatTime(myTime, "YYYY-MM-DD") + +@method formatTime +@param {String} time The timstamp, can be string or unix format +@param {String} format the format string, can also be "iso", to format to ISO string, or "fromnow" +@return {String} The formated time +**/ +// Helpers.formatTime = function(time, format) { //parameters + +// // make sure not existing values are not Spacebars.kw +// if(format instanceof Spacebars.kw) +// format = null; + +// if(time) { + +// if(_.isString(format) && !_.isEmpty(format)) { + +// if(format.toLowerCase() === 'iso') +// time = Helpers.moment(time).toISOString(); +// else if(format.toLowerCase() === 'fromnow') { +// // make reactive updating +// Helpers.rerun['10s'].tick(); +// time = Helpers.moment(time).fromNow(); +// } else +// time = Helpers.moment(time).format(format); +// } + +// return time; + +// } else +// return ''; +// }; + +/** +Formats a given number + + Helpers.formatNumber(10000, "0.0[000]") + +@method formatNumber +@param {Number|String|BigNumber} number the number to format +@param {String} format the format string e.g. "0.0[000]" see http://numeraljs.com for more. +@return {String} The formated time +**/ +// Helpers.formatNumber = function(number, format){ +// if(format instanceof Spacebars.kw) +// format = null; + +// if(number instanceof BigNumber) +// number = number.toString(10); + +// format = format || '0,0.0[0000]'; + +// if(!_.isFinite(number)) +// number = numeral().unformat(number); + +// if(_.isFinite(number)) +// return numeral(number).format(format); +// }; + +/** +Formats a given number toa unit balance + + Helpers.formatBalance(10000, "0.0[000]") + +@method formatBalance +@param {Number|String|BigNumber} number the number to format +@param {String} format the format string e.g. "0.0[000]" see http://numeraljs.com for more. +@return {String} The formated balance including the unit +**/ +// Helpers.formatBalance = function(number, format){ +// number = web3.fromWei(number, LocalStore.get('etherUnit')); + +// return Helpers.formatNumber(number, format) +' '+ LocalStore.get('etherUnit'); +// }; diff --git a/interface/client/lib/helpers/templateHelpers.js b/interface/client/lib/helpers/templateHelpers.js new file mode 100644 index 0000000..c2296f7 --- /dev/null +++ b/interface/client/lib/helpers/templateHelpers.js @@ -0,0 +1,167 @@ +/** +Helper functions + +@module Helpers +**/ + +/** +Global template helpers + +@class TemplateHelpers +@constructor +**/ + +/** +A simple template helper to log objects in the console. + +@method (debug) +**/ +Template.registerHelper('debug', function(object) { + console.log(object); +}); + +/** +Returns the current block + +@method (CurrentBlock) +**/ +Template.registerHelper('CurrentBlock', function() { + return EthBlocks.latest; +}); + +/** +Return the dirname. + +@method (dirname) +**/ +Template.registerHelper('dirname', function() { + return window.dirname; +}); + +/** +Return the Mist API. + +@method (mist) +**/ +Template.registerHelper('mist', function() { + return window.mist; +}); + +/** +Return the app mode. + +@method (mode) +**/ +Template.registerHelper('mode', function() { + return window.mistMode; +}); + +/** +Return the friendly app name. + +@method (appName) +**/ +Template.registerHelper('appName', function() { + return window.mistMode === 'mist' ? 'Mist' : 'EtherCore Wallet'; +}); + +/** +Return the app icon path. + +@method (iconPath) +**/ +Template.registerHelper('appIconPath', function() { + return ( + 'file://' + window.dirname + '/icons/' + window.mistMode + '/icon2x.png' + ); +}); + +/** +Get all accounts + +@method (accounts) +**/ +Template.registerHelper('accounts', function(identity) { + return EthAccounts.find({}, { sort: { name: 1 } }); +}); + +/** +Check if the given wallet is a watch only wallet, by checking if we are one of owners in the wallet. + +@method (isWatchOnly) +@param {String} id the id of the wallet to check +**/ +Template.registerHelper('isWatchOnly', Helpers.isWatchOnly); + +/** +Return the right wallet icon + +@method (walletIcon) +**/ +Template.registerHelper('walletIcon', function() { + var icon = ''; + + if (this.type === 'wallet') { + if (Helpers.isWatchOnly(this._id)) { + icon = ''; + } else { + icon = ''; + } + } else if (this.type === 'account') { + icon = ''; + } + + return new Spacebars.SafeString(icon); +}); + +/** +Get the account name or display the address + +@method (accountNameOrAddress) +@param {String} address +*/ +Template.registerHelper('accountNameOrAddress', function(address) { + var account = EthAccounts.findOne({ address: address }); + if (account) { + return account.name; + } else { + return address; + } +}); + +/** +Formats a timestamp to any format given. + + {{formatTime myTime "YYYY-MM-DD"}} + +@method (formatTime) +@param {String} time The timstamp, can be string or unix format +@param {String} format the format string, can also be "iso", to format to ISO string, or "fromnow" +//@param {Boolean} realTime Whether or not this helper should re-run every 10s +@return {String} The formated time +**/ +Template.registerHelper('formatTime', Helpers.formatTime); + +/** +Formats a number. + + {{formatNumber myNumber "0,0.0[0000]"}} + +@method (formatNumber) +@param {String} number +@param {String} format the format string +@return {String} The formatted number +**/ +Template.registerHelper('formatNumber', Helpers.formatNumber); + +/** +Formats a number. + + {{formatBalance myNumber "0,0.0[0000]"}} + +@method (formatBalance) +@param {String} number +@param {String} format the format string +@return {String} The formatted number +**/ +Template.registerHelper('formatBalance', Helpers.formatBalance); diff --git a/interface/client/lib/signatures.js b/interface/client/lib/signatures.js new file mode 100644 index 0000000..de0705a --- /dev/null +++ b/interface/client/lib/signatures.js @@ -0,0 +1,6462 @@ +window.SIGNATURES = { + '0x063925c8': ['scheduleCall(bytes,uint256,uint256)'], + '0x523ccfa8': ['isKnownCall(address)'], + '0x0a16697a': ['targetBlock()'], + '0xea8a1af0': ['cancel()'], + '0xae45850b': ['schedulerAddress()'], + '0x3f4be889': ['callContractAddress()'], + '0x62986e27': ['Canary(address,uint16)'], + '0x8129fc1c': ['initialize()'], + '0x4a420138': ['scheduleHeartbeat()'], + '0x3defb962': ['heartbeat()'], + '0x4136aa35': ['isAlive()'], + '0xac9873c7': ['CanaryV7()'], + '0x334dc700': ['CanaryV7Testnet()'], + '0x0b9e9817': ['CanaryV7FastTestnet()'], + '0xecf6eb22': ['setConfigAddress(bytes,address)'], + '0x6099af40': ['setConfigBool(bytes,bool)'], + '0x0baaaed9': ['setConfigBytes(bytes,bytes)'], + '0xa288fb1f': ['setConfigUint(int256,bytes,uint256)'], + '0x9e997121': ['getConfigAddress(bytes)'], + '0x087e055a': ['getConfigBool(bytes)'], + '0xb38415f3': ['getConfigBytes(bytes)'], + '0x015e4f3a': ['getConfigUint(int256,bytes)'], + '0x70480275': ['addAdmin(address)'], + '0x1785f53c': ['removeAdmin(address)'], + '0x43e6125d': ['Badge(address)'], + '0x4e30a66c': ['safeToAdd(uint256,uint256)'], + '0xc74c251f': ['addSafely(uint256,uint256)'], + '0xe74b9d11': ['safeToSubtract(uint256,uint256)'], + '0x3416f9d4': ['subtractSafely(uint256,uint256)'], + '0x70a08231': ['balanceOf(address)'], + '0xa9059cbb': ['transfer(address,uint256)'], + '0x23b872dd': ['transferFrom(address,address,uint256)'], + '0x095ea7b3': ['approve(address,uint256)'], + '0xdd62ed3e': ['allowance(address,address)'], + '0xd35f4a99': ['mint(int256,address,uint256)'], + '0x13af4035': ['setOwner(address)'], + '0x26070774': ['Token(address)'], + '0x80a23ddf': ['mintBadge(int256,address,uint256)'], + '0x2b297f9e': ['registerDao(address)'], + '0x6637b882': ['setDao(address)'], + '0x3f2965f0': ['registerSeller(address)'], + '0xac900c2d': ['unregisterSeller(address)'], + '0x18160ddd': ['totalSupply()'], + '0xdfcbb794': ['TrustFund(address,uint256,address)'], + '0x69d89575': ['releaseFunds()'], + '0xdd2ad311': ['scheduleCall(bytes,uint256)'], + '0x7f497550': ['scheduleTransfer(address,uint256,uint256)'], + '0x1e39499d': ['scheduleCall(address,bytes,uint256)'], + '0x075fe877': ['scheduleCall(address,bytes,uint256,uint256)'], + '0x6b069710': ['scheduleCall(address,bytes,uint256,uint256,uint8)'], + '0xb7aec6a5': ['scheduleCall(address,bytes,uint256,uint256,uint8,uint256)'], + '0xf37b437b': [ + 'scheduleCall(address,bytes,uint256,uint256,uint8,uint256,uint256)' + ], + '0xd826f88f': ['reset()'], + '0x638560cf': ['registerBool(address,bool)'], + '0x9872a20a': ['registerUInt(address,uint256)'], + '0x1fb291cb': ['registerInt(address,int256)'], + '0x9aa26f06': ['registerBytes32(address,bytes)'], + '0x5dcbac7a': ['registerBytes(address,bytes)'], + '0x31b0795c': ['registerAddress(address,address)'], + '0x9c1500f0': [ + 'registerMany(address,uint256,int256,uint256,bytes,address,bytes)' + ], + '0x5bfdc700': ['registerData(address,int256,bytes,address)'], + '0x5dfc2e4a': ['noop()'], + '0x5629c6d9': ['doExecution(address)'], + '0x1db71ffb': ['doLoops(uint256)'], + '0x6558488a': ['scheduleSetBool(address,uint256,bool)'], + '0x6f374a12': ['setBool()'], + '0xa71f94c8': ['scheduleSetUInt(address,uint256,uint256)'], + '0x54fd4d50': ['version()'], + '0x9378a9e2': ['setUInt(uint256)'], + '0x747586b8': ['setInt(int256)'], + '0xe30081a0': ['setAddress(address)'], + '0x46d667db': ['setBytes32(bytes)'], + '0xda359dc8': ['setBytes(bytes)'], + '0xbadbaa3c': ['setCallData()'], + '0x999a9965': ['setMany(uint256,int256,uint256,bytes,address,bytes)'], + '0xf46c50dc': ['doFail()'], + '0x3809c0bf': ['doInfinite()'], + '0x9941e3d0': ['setCallAddress(address)'], + '0xac1b14ff': ['proxyCall(uint256)'], + '0x21835af6': ['__dig(uint256)'], + '0x2e9c5e77': ['doStackExtension(uint256)'], + '0x971c803f': ['getMinimumStackCheck()'], + '0x586a69fa': ['getMaximumStackCheck()'], + '0x98e00e54': ['getCallWindowSize()'], + '0xc0f68859': ['getMinimumGracePeriod()'], + '0x8e46afa9': ['getDefaultGracePeriod()'], + '0x98c9cdf4': ['getMinimumCallGas()'], + '0x26a7985a': ['getMaximumCallGas()'], + '0x96cff3df': ['getMinimumCallCost(uint256,uint256)'], + '0xb152f19e': ['getFirstSchedulableBlock()'], + '0xea27a881': ['getMinimumEndowment(uint256,uint256,uint256,uint256)'], + '0x5548c837': ['Deposit(address,address,uint256)'], + '0x7fcf532c': ['Withdrawal(address,uint256)'], + '0x5c54305e': ['InsufficientFunds(address,uint256,uint256)'], + '0x12c82bcc': ['sendRobust(address,uint256)'], + '0xc6ab4514': ['sendRobust(address,uint256,uint256)'], + '0x6d5433e6': ['max(uint256,uint256)'], + '0xc5699d68': ['_compare(int256,bytes,int256)'], + '0x45fe6e2a': ['Scheduler()'], + '0x3017fe24': ['callAPIVersion()'], + '0xe6470fbe': ['updateDefaultPayment()'], + '0xbbc6eb1f': ['getDefaultDonation()'], + '0x1e74a2d3': ['getMinimumEndowment()'], + '0xaff21c65': ['getMinimumEndowment(uint256)'], + '0xf158458c': ['getMinimumEndowment(uint256,uint256)'], + '0x7c73f846': ['getMinimumEndowment(uint256,uint256,uint256)'], + '0x1b4fa6ab': ['getDefaultStackCheck()'], + '0xdbfef710': ['getDefaultRequiredGas()'], + '0xc3a2c0c3': ['scheduleCall()'], + '0x112e39a8': ['scheduleCall(uint256)'], + '0x67beaccb': ['scheduleCall(bytes)'], + '0xf4bbfd6a': ['scheduleCall(bytes,bytes)'], + '0x04509918': ['scheduleCall(address)'], + '0xa045fdff': ['scheduleCall(address,bytes)'], + '0x4b63e601': ['scheduleCall(address,uint256,bytes)'], + '0xa6cb9e64': ['scheduleCall(address,bytes,bytes)'], + '0x3fbb539d': ['scheduleCall(address,bytes,uint256,bytes)'], + '0xa00aede9': ['scheduleCall(uint256,address)'], + '0xb5b33eda': ['scheduleCall(address,uint256)'], + '0xd8e5c048': ['scheduleCall(address,uint256,uint256)'], + '0x75f45878': ['scheduleCall(bytes,bytes,uint256)'], + '0x349501b7': ['checkDepth(uint256)'], + '0xa0bd3c0f': ['scheduleCall(address,bytes,bytes,uint256)'], + '0xc17e6817': ['sendSafe(address,uint256)'], + '0x76ca0c77': ['scheduleCall(address,bytes,uint256,bytes,uint256)'], + '0xb5d0f16e': ['getGasScalar(uint256,uint256)'], + '0x49942ccb': ['scheduleCall(bytes,bytes,uint256,uint256)'], + '0xf5562753': ['getClaimAmountForBlock(uint256)'], + '0x64bd87d6': ['scheduleCall(address,bytes,bytes,uint256,uint256)'], + '0xa9d2293d': ['lastClaimBlock()'], + '0x0e554bd8': ['scheduleCall(bytes,uint256,uint256,uint8)'], + '0xcc3471af': ['maxClaimBlock()'], + '0xaa497b9d': ['scheduleCall(address,uint256,bytes,uint256,uint256,uint8)'], + '0x0fd1f94e': ['firstClaimBlock()'], + '0x67a59d91': ['scheduleCall(address,bytes,bytes,uint256,uint256,uint8)'], + '0x4571d4c4': [ + 'FutureCall(address,uint256,uint16,address,bytes,bytes,uint256,uint256,uint256)' + ], + '0xc6236a5c': ['scheduleCall(bytes,uint256,uint256,uint8,uint256)'], + '0xc19d93fb': ['state()'], + '0x40953102': [ + 'scheduleCall(address,uint256,bytes,uint256,uint256,uint8,uint256)' + ], + '0x7d298ee3': ['beforeExecute(address,uint256)'], + '0xe7329e71': ['scheduleCall(bytes,bytes,uint256,uint256,uint8,uint256)'], + '0x09b30ed5': ['afterExecute(address)'], + '0xd6eafd08': ['scheduleCall(address,bytes,bytes,uint8,uint256[4])'], + '0x67ce940d': ['getOverhead()'], + '0x991ffd4e': [ + 'scheduleCall(address,bytes,bytes,uint256,uint256,uint8,uint256)' + ], + '0x137c638b': ['getExtraGas()'], + '0xd13d1ace': [ + 'scheduleCall(bytes,bytes,uint16,uint8,uint256,uint256,uint256,uint256,uint256)' + ], + '0xf6b4dfb4': ['contractAddress()'], + '0x38eee93e': ['scheduleCall(address,bytes,bytes,uint16,uint8,uint256[5])'], + '0xca94692d': ['abiSignature()'], + '0x9f927be7': ['getNextCall(uint256)'], + '0x48107843': ['getNextCallSibling(address)'], + '0x4e417a98': ['callData()'], + '0xd62457f6': ['callValue()'], + '0x37f4c00e': ['anchorGasPrice()'], + '0x974654f4': ['requiredGas()'], + '0x2f95b833': ['requiredStackDepth()'], + '0xd379be23': ['claimer()'], + '0x830953ab': ['claimAmount()'], + '0x3233c686': ['claimerDeposit()'], + '0x09241200': ['wasSuccessful()'], + '0xc6803622': ['wasCalled()'], + '0x95ee1221': ['isCancelled()'], + '0x4f059a43': ['getClaimAmountForBlock()'], + '0xb0f07e44': ['registerData()'], + '0x4e71d92d': ['claim()'], + '0x24032866': ['checkExecutionAuthorization(address,uint256)'], + '0x61461954': ['execute()'], + '0x0cb749b6': [ + 'FutureBlockCall(address,uint256,uint8,address,bytes,bytes,uint256,uint256,uint16,uint256,uint256)' + ], + '0x4500054f': ['isCancellable()'], + '0xa3912ec8': ['receiveEther()'], + '0x612e45a3': ['newProposal(address,uint256,string,bytes,uint256,bool)'], + '0xeceb2945': ['checkProposalCode(uint256,address,uint256,bytes)'], + '0xc9d27afe': ['vote(uint256,bool)'], + '0x237e9492': ['executeProposal(uint256,bytes)'], + '0x82661dc4': ['splitDAO(uint256,address)'], + '0x6837ff1e': ['newContract(address)'], + '0x749f9889': ['changeAllowedRecipients(address,bool)'], + '0xe33734fd': ['changeProposalDeposit(uint256)'], + '0xa1da2fb9': ['retrieveDAOReward(bool)'], + '0xcc9ae3f6': ['getMyReward()'], + '0x8a00a82f': ['withdrawRewardFor(address)'], + '0x4e10c3ee': ['transferWithoutReward(address,uint256)'], + '0xdbde1988': ['transferFromWithoutReward(address,address,uint256)'], + '0x78524b2e': ['halveMinQuorum()'], + '0x8d7af473': ['numberOfProposals()'], + '0xbe7c29c1': ['getNewDAOAddress(uint256)'], + '0xfbac3951': ['isBlocked(address)'], + '0x2632bf20': ['unblockMe()'], + '0x0386a016': ['closeProposal(uint256)'], + '0x48027610': ['transferPaidOut(address,address,uint256)'], + '0x8400c307': ['isRecipientAllowed(address)'], + '0x39d1f908': ['actualBalance()'], + '0xf42ac1de': ['minQuorum(uint256)'], + '0xd21b84ac': ['createNewDAO(address)'], + '0xd92ebe46': [ + 'createDAO(address,uint256,uint256,uint256,string,string,uint8)' + ], + '0xebae35a6': ['DAOTokenCreationProxyTransferer(address,address)'], + '0xbe2430fe': ['sendValues()'], + '0x013cf08b': ['proposals(uint256)'], + '0x8bfc2f33': ['delegateDAOTokens(uint256)'], + '0xe417291b': ['undelegateDAOTokens(uint256)'], + '0x4da74ee6': ['setVoteIntention(uint256,bool,bool,string)'], + '0xf98a4eca': ['executeVote(uint256)'], + '0xe49dcee9': ['fixTokens()'], + '0xde0ff7c5': ['getEther()'], + '0xd9fe60f3': ['DTHPool(address,address,uint256,string,string,string)'], + '0xdaa283c8': ['__callback(bytes,string)'], + '0x0221038a': ['payOut(address,uint256)'], + '0x1fd96b69': ['ManagedAccount(address,bool)'], + '0x1adf2d1a': [ + 'Offer(address,address,bytes,uint256,uint256,uint128,uint256)' + ], + '0x1bcad37a': ['getTotalCost()'], + '0x60213b88': ['getInitialWithdrawal()'], + '0x42d16748': ['getMinDailyWithdrawalLimit()'], + '0xd6b4ec12': ['getDailyWithdrawalLimit()'], + '0x262c0b72': ['getPayoutFreezePeriod()'], + '0xb6cb405b': ['getContractor()'], + '0x43bf718e': ['getHashOfTheProposalDocument()'], + '0x0c0662a8': ['getLastWithdrawal()'], + '0xb29ae23f': ['getDateOfSignature()'], + '0x59dc735c': ['getClient()'], + '0x72b75585': ['getOriginalClient()'], + '0xa00ce377': ['getIsContractValid()'], + '0xd44f2d3d': ['getInitialWithdrawalDone()'], + '0x1f7b8622': ['getVotingDeadline()'], + '0x2ca15122': ['sign()'], + '0xedfbf7b6': ['setVotingDeadline(uint256)'], + '0x6a7fc8b7': ['setDailyWithdrawLimit(uint128)'], + '0x0c08bf88': ['terminate()'], + '0x3ccfd60b': ['withdraw()'], + '0x14918f5e': ['performInitialWithdrawal()'], + '0xb6ed9f15': ['PFOffer(address,address,bytes,uint256,uint256,uint128)'], + '0x350d141e': ['getWasApprovedBeforeDeadline()'], + '0x20768ee8': ['getProposalID()'], + '0xffb7bfba': ['watchProposal(uint256)'], + '0xe45ebe93': ['checkVoteStatus()'], + '0x5d268629': ['Refund()'], + '0x29f1bff4': ['withdrawFromChildDAO(uint256)'], + '0x943b0747': [ + 'RewardOffer(address,address,bytes,uint256,uint256,uint128,uint256)' + ], + '0x1632070c': ['setRewardDivisor(uint256)'], + '0xe32e9f22': ['setDeploymentReward(uint256)'], + '0xe9540395': ['getRewardDivisor()'], + '0x525b25b1': ['getDeploymentReward()'], + '0x51cff8d9': ['withdraw(address)'], + '0xbaac5300': ['createTokenProxy(address)'], + '0x590e1ae3': ['refund()'], + '0x1f2dc5ef': ['divisor()'], + '0x69431ab6': ['TokenCreation(uint256,uint256,address,string,string,uint8)'], + '0x36dfe260': ['payOneTimeReward()'], + '0x7842a3a4': ['payReward()'], + '0xadf59f99': ['query(uint256,string,string)'], + '0xc51be90f': ['query_withGasLimit(uint256,string,string,uint256)'], + '0x77228659': ['query2(uint256,string,string,string)'], + '0x85dee34c': ['query2_withGasLimit(uint256,string,string,string,uint256)'], + '0x524f3889': ['getPrice(string)'], + '0x2ef3accc': ['getPrice(string,uint256)'], + '0x60f66701': ['useCoupon(string)'], + '0x688dcfd7': ['setProofType(bytes1)'], + '0x38cc4831': ['getAddress()'], + '0x6b3fdc5a': ['oraclize_setNetwork(uint8)'], + '0x489306eb': ['oraclize_query(string,string)'], + '0x7975c56e': ['oraclize_query(uint256,string,string)'], + '0x056e1059': ['oraclize_query(uint256,string,string,uint256)'], + '0xae152cf4': ['oraclize_query(string,string,uint256)'], + '0x346b306a': ['oraclize_query(string,string,string)'], + '0x5731f357': ['oraclize_query(uint256,string,string,string)'], + '0x65a4dfb3': ['oraclize_query(uint256,string,string,string,uint256)'], + '0x2c85f8e0': ['oraclize_query(string,string,string,uint256)'], + '0xbcf175c8': ['oraclize_cbAddress()'], + '0xd7c26adb': ['oraclize_setProof(bytes1)'], + '0xa6823189': ['parseAddr(string)'], + '0xe8641652': ['strCompare(string,string)'], + '0x8a0807b7': ['indexOf(string,string)'], + '0xff74927b': ['strConcat(string,string)'], + '0x42346c5e': ['parseInt(string)'], + '0xbf4d89b5': ['parseInt(string,uint256)'], + '0xac996e7e': ['resolvePledging()'], + '0x45a3b0bf': ['resolveFailPledge()'], + '0x299e7318': ['resolveVoting()'], + '0x921f98bb': ['resolveFailVote()'], + '0x1afccfa5': ['Proposal(address,address,address,bytes,bool)'], + '0xaed8f3da': ['partsPerBillion(uint256,uint256)'], + '0x1ba326c4': ['calcShare(uint256,uint256,uint256)'], + '0xd630bd53': ['pledgeApprove(uint256)'], + '0x40b31937': ['pledgeDecline(uint256)'], + '0xdacaeb07': ['pledge(bool,uint256)'], + '0x5a9b0b89': ['getInfo()'], + '0x4e69d560': ['getStatus()'], + '0x6386c1c7': ['getUserInfo(address)'], + '0x7daa10ce': ['getMyInfo()'], + '0xd78c20ff': ['voteApprove(uint256)'], + '0x27a5c7c6': ['voteDecline(uint256)'], + '0x10e6e06c': ['vote(bool,uint256)'], + '0x052b81c7': ['releaseBadges()'], + '0xa96f8668': ['releaseTokens()'], + '0xed01bf29': ['budget()'], + '0xdcc0ccf3': ['Dao(address)'], + '0x8a3bc2bc': ['iPropose(bytes,uint256,bool)'], + '0xbade6033': ['propose(bytes,uint256)'], + '0xd205ad7d': ['proposeDissolve(bytes)'], + '0xc7f758a8': ['getProposal(uint256)'], + '0xc89f2ce4': ['funds()'], + '0xc4254c7b': ['CoreWallet()'], + '0xb69ef8a8': ['balance()'], + '0x67c2a360': ['authorizeUser(address)'], + '0x478aa69e': ['unauthorizeUser(address)'], + '0x267c8507': ['authorizeManager(address)'], + '0x17623e5b': ['unauthorizeManager(address)'], + '0xf3fef3a3': ['withdraw(address,uint256)'], + '0xc8c01a55': ['request(address,uint256)'], + '0xb759f954': ['approve(uint256)'], + '0xa0355f4e': ['decline(uint256)'], + '0xfedfd535': ['Config()'], + '0xf697a0ed': ['ppb(uint256,uint256)'], + '0xab519020': ['calcShare(uint256,uint256)'], + '0x6d568c43': ['weiToCents(uint256)'], + '0x4a5dddd2': ['proxyPurchase(address)'], + '0x8de93222': ['purchase(address,uint256)'], + '0x1959a002': ['userInfo(address)'], + '0x85b31d7b': ['myInfo()'], + '0x4551b1d7': ['ProxyPayment(address,address)'], + '0x6d98e9fc': ['totalWei()'], + '0xf0e959f9': ['TokenSales(address)'], + '0xbc126ba1': ['totalCents()'], + '0xdb83694c': ['getSaleInfo()'], + '0xddeae033': ['claimFor(address)'], + '0x0c77a697': ['claimFounders()'], + '0x7d3d6522': ['goalReached()'], + '0x1ed24195': ['getPeriod()'], + '0x0b97bc86': ['startDate()'], + '0x3f5b7675': ['periodTwo()'], + '0xbb7859b5': ['periodThree()'], + '0xc24a0f8b': ['endDate()'], + '0xa4fd6f56': ['isEnded()'], + '0x8d68cf59': ['sendFunds()'], + '0x5bd74490': ['regProxy(address,address)'], + '0x8c0e2a31': ['regProxy(address)'], + '0xb7fba4d3': ['getProxy(address)'], + '0x8006745b': ['getPayout(address)'], + '0xa69df4b5': ['unlock()'], + '0x8c3c4b34': ['getSaleStatus()'], + '0xcea943ee': ['getSaleConfig()'], + '0x034187fd': ['setEthToCents(uint256)'], + '0xb1adc241': ['BalanceDB()'], + '0x6c9c2faf': ['getSupply()'], + '0xf8b2cb4f': ['getBalance(address)'], + '0xe30443bc': ['setBalance(address,uint256)'], + '0x21e5383a': ['addBalance(address,uint256)'], + '0xcf8eeb7e': ['subBalance(address,uint256)'], + '0xd70cf105': ['moveBalance(address,address,uint256)'], + '0xf2371fb3': ['grantGiveableKudos(address,uint256)'], + '0xce79add1': ['givableBalanceOf(address)'], + '0x2b25a7e4': ['giveKudos(address,uint256)'], + '0x1dbf3bc7': ['spend(uint256)'], + '0xda1441cd': ['KudosBank(uint256)'], + '0xf009347d': ['KudosProxy(address)'], + '0xf2fde38b': ['transferOwnership(address)'], + '0xdf32754b': ['owned()'], + '0xb2aac51f': ['lookupUser(string)'], + '0x0e54b872': ['registerUser(string,address)'], + '0xd40a71fb': ['step1()'], + '0x8f4ed333': ['step2()'], + '0xdf4ec249': ['step3()'], + '0xfb5d7376': ['step4()'], + '0x4fb4bcec': ['step5()'], + '0xeb7c6f72': ['step6()'], + '0xbddd3a6b': ['step7()'], + '0xa3221c8e': ['step8()'], + '0x0a9254e4': ['setUp()'], + '0x775c300c': ['deploy()'], + '0x845051d3': ['testContractsNotNull()'], + '0x354b2735': ['testDeploy()'], + '0x9380b8e7': ['testFailAddingMembers()'], + '0xd83a8d11': ['testProposing()'], + '0xc1257bad': ['testPassingAProposal()'], + '0x524e4e61': ['testDistribution()'], + '0xb0166b04': ['testTransferringMkr()'], + '0x867904b4': ['issue(address,uint256)'], + '0x1de38038': ['makercoin(uint256)'], + '0x775a8f5e': ['toBytes(uint256)'], + '0xc490a266': ['toUInt(bytes)'], + '0x1f8947c1': ['extractUint(int256,bytes,uint256,uint256)'], + '0x0761a004': ['step(uint256,bytes)'], + '0x7b352962': ['isFinished()'], + '0xcf31e9fe': ['getOutputHash()'], + '0x3c9a4baa': ['requestOutput(bytes)'], + '0xfd735602': ['executeN()'], + '0xc64e8bc0': ['executeN(uint256)'], + '0x665beae7': ['ExecutableBase(bytes)'], + '0xc58343ef': ['getRequest(uint256)'], + '0x7a479160': ['getRequestArgs(uint256)'], + '0x5944427b': ['getRequestResult(uint256)'], + '0xf95b5a58': ['getInitialAnswer(uint256)'], + '0xcaaf2dd7': ['getInitialAnswerResult(uint256)'], + '0xafc24e3d': ['getChallengeAnswer(uint256)'], + '0x0411bca8': ['getChallengeAnswerResult(uint256)'], + '0x13a396d8': ['getRequiredDeposit(bytes)'], + '0x5023d124': ['TestFactory()'], + '0x9bee757b': ['requestExecution(bytes,uint256)'], + '0x3015394c': ['cancelRequest(uint256)'], + '0x5ea187c9': ['BuildByteArray(bytes)'], + '0xc70d169d': ['answerRequest(uint256,bytes)'], + '0xe10e5dce': ['_build(bytes)'], + '0xa8978434': ['softResolveAnswer(uint256)'], + '0x8143f8a8': ['totalGas(bytes)'], + '0xfcce2622': ['challengeAnswer(uint256,bytes)'], + '0x8e3d4e5e': ['Fibonacci(bytes)'], + '0x7b0383b2': ['initializeDispute(uint256)'], + '0x6dc3edcf': ['executeExecutable(uint256,uint256)'], + '0x05261aea': ['finalize(uint256)'], + '0x96e438a1': ['reclaimDeposit(uint256)'], + '0x29d28aad': ['Broker(address)'], + '0x5d3c1d4c': ['_getRequest(uint256)'], + '0xa6b1caa3': ['gasScalar(uint256)'], + '0xaf29e720': ['remainingGasFund(uint256)'], + '0x6835f32c': ['build(bytes)'], + '0x7ae2b5c7': ['min(uint256,uint256)'], + '0x53770f9a': ['isStateless()'], + '0x9c5d7030': ['reimburseGas(uint256,address,uint256,uint256)'], + '0x5d8227e6': ['FactoryBase(string,string,string)'], + '0xd8f012c6': ['StatelessFactory(string,string,string)'], + '0x03427656': ['getDefaultSoftResolutionBlocks()'], + '0x4f223fe3': ['StatefulFactory(string,string,string)'], + '0xf1448e10': ['requestExecution(bytes)'], + '0x4c0e207a': ['__outputCallback(uint256)'], + '0xd6c19fe0': ['build(bytes,uint256,uint256,address)'], + '0xe59d843a': ['Replicator(bytes,uint256,uint256,address)'], + '0x50c42921': ['replicate()'], + '0xb0604a26': ['schedule()'], + '0xdda3342b': ['ReplicatorFactory()'], + '0xa6b197aa': ['Order(address,uint256)'], + '0x67b830ad': ['fillOrder(uint256)'], + '0x9c7264d7': ['fillOrder(address,uint256)'], + '0xafd8c8c4': ['GasProxy(address,address)'], + '0x16f3cb5e': ['__kill()'], + '0x4d536fe3': ['doit()'], + '0x881be8f7': ['undo()'], + '0x60fe47b1': ['set(uint256)'], + '0x5bec9e67': ['infinite()'], + '0xce869a64': ['fails()'], + '0x1aca00fd': ['variable(uint256)'], + '0xd81ab0c1': ['invoke(uint256,address,address,bytes)'], + '0xf666323e': ['UUIDProvider()'], + '0x60585358': ['getByte()'], + '0x4b0bbf84': ['addEntropy()'], + '0x5404bbf7': ['getEntropy()'], + '0x31757f2e': ['collisionCount()'], + '0x352d2790': ['UUID4()'], + '0xd69450d5': ['setUUID4Bytes(bytes)'], + '0x3ae01f84': ['USDOracle()'], + '0x104d5fdd': ['getPriceProxy()'], + '0x531b97d7': ['oneCentOfWei()'], + '0xb845c9a2': ['WEI()'], + '0x1bf6c21b': ['USD()'], + '0x943a32bc': ['Relay(address)'], + '0x6edbd134': ['hasHash()'], + '0xb00140aa': ['getHash(bytes)'], + '0x54ed7b6e': ['addHash(bytes)'], + '0xe1041d86': ['__throw()'], + '0x25495998': ['getMinimumConsumerDeposit()'], + '0xf1076703': ['getVerificationId(address,bytes,bytes)'], + '0x8e2c6f4d': ['initiateVerification(address,bytes,bytes)'], + '0x5714f6a1': ['getTotalAvailableRelays()'], + '0xd2fb8787': ['recordExists(bytes)'], + '0x8e52cb51': ['getRecordKey(bytes,bytes,bytes)'], + '0x9ee035c9': ['lookupCanonicalFormat(bytes)'], + '0x50ea1932': ['lookupISO3116_1_alpha_2(bytes)'], + '0xfa68b4ce': ['lookupISO3116_1_alpha_3(bytes)'], + '0xd98d011d': ['getCandidateKey(bytes,bytes,bytes,bytes)'], + '0x70b1d9d4': ['requestCanonicalFormat(bytes)'], + '0x27bc39c0': ['submitCanonicalCandidate(bytes,bytes,bytes,bytes)'], + '0xe9dc0614': ['vote(bytes)'], + '0xa553a597': ['configure(uint256,uint256,uint8,address)'], + '0x2852b71c': ['accept()'], + '0x4dc415de': ['reject()'], + '0xc631b292': ['closeVoting()'], + '0x378a2178': ['tallyVotes()'], + '0xbc5d0f65': ['beginExecution()'], + '0x8124bb0f': ['continueExecution()'], + '0xcabd27de': ['Motion(address)'], + '0xcc2c2bcf': ['MotionFactory(string,string,string)'], + '0x6ad2a0b3': ['buildContract(address)'], + '0x0a3b0a4f': ['add(address)'], + '0x29092d0e': ['remove(address)'], + '0xf6a3d24e': ['exists(address)'], + '0xefc81a8c': ['create()'], + '0x207c64fb': ['validate(address)'], + '0x5bb47808': ['setFactory(address)'], + '0x1327d3d8': ['setValidator(address)'], + '0x68f5aa0f': ['setShareholderDB(address)'], + '0x8f99ea43': ['setDividendDB(address)'], + '0x62e05175': ['setMotionDB(address)'], + '0x611f69de': ['__proxy_motion(address,uint256,uint256,bytes)'], + '0x144fa6d7': ['setToken(address)'], + '0x13827950': ['getShareholderDB()'], + '0x299a7bcc': ['setOwner(address,address)'], + '0xf340fa01': ['deposit(address)'], + '0x9555a942': ['withdrawFrom(address,address,uint256)'], + '0x3b8e6f2e': ['balanceAt(address,uint256)'], + '0x3397ca17': ['numBalanceRecords(address)'], + '0xcbf1304d': ['balances(address,uint256)'], + '0x9a97043b': ['depositIdx(address)'], + '0xb9f28076': ['historyIdx(address)'], + '0xa0afd731': ['dividendBalance(address)'], + '0xbbd4e8c9': ['numDeposits()'], + '0xb6b55f25': ['deposit(uint256)'], + '0x311d5a2a': ['recordBalance(address)'], + '0x5437b39b': ['hasUnprocessedDividends(address)'], + '0x57f4d5ec': ['processDividends(address,uint256)'], + '0xe7334156': ['processNextDeposit(address)'], + '0x7f480f9d': ['processDividends(address)'], + '0xb89a73cb': ['isShareholder(address)'], + '0x08933d11': ['getJoinBlock(address)'], + '0xa200dc73': ['getNextShareholder(address)'], + '0xb722a9ef': ['getPreviousShareholder(address)'], + '0xc45aa04c': ['queryShareholders(bytes,uint256)'], + '0xdb29fe12': ['addShareholder(address)'], + '0x9babdad6': ['removeShareholder(address)'], + '0x8e2a6470': ['allocateShares(address,uint256)'], + '0x4d47feaa': ['ShareholderDB(uint256)'], + '0xa4898fd5': ['deployContract(address)'], + '0x96c52fc3': ['____forward(address,uint256,uint256,bytes)'], + '0x567dbf18': ['__forward(address,uint256,uint256,bytes)'], + '0xfd782de5': ['Proxy()'], + '0xb36df681': ['ExecutableBase()'], + '0x6f698fb5': ['setMinimumQuorum(uint256)'], + '0xa140e79c': ['setMinimumDebatePeriod(uint256)'], + '0x00e46700': ['setMinimumPassPercentage(uint8)'], + '0xb7c93330': ['ResourcePoolTester()'], + '0xf59f99ee': ['createNextGeneration()'], + '0x0bebd0f9': ['addAddressToGeneration(address,uint256)'], + '0xf8b11853': ['getGenerationStartAt(uint256)'], + '0x306b031d': ['getGenerationEndAt(uint256)'], + '0x67854643': ['getGenerationMemberLength(uint256)'], + '0x38fff2d0': ['getPoolId()'], + '0xc831391d': ['getPoolOverlapSize()'], + '0x61649472': ['getPoolFreezePeriod()'], + '0xed2b8e0b': ['getPoolRotationDelay()'], + '0xc630f92b': ['canEnterPool()'], + '0x8dd5e298': ['canEnterPool(address)'], + '0x50a3bd39': ['enterPool()'], + '0xffd10e07': ['enterPool(address)'], + '0x5a5383ac': ['canExitPool()'], + '0xb010d94a': ['canExitPool(address)'], + '0x29917954': ['exitPool()'], + '0xba5a2d33': ['exitPool(address)'], + '0xb0171fa4': ['getCurrentGenerationId()'], + '0xa502aae8': ['getNextGenerationId()'], + '0x7772a380': ['isInGeneration(address,uint256)'], + '0x7c47965e': ['isInCurrentGeneration()'], + '0x400aae08': ['isInCurrentGeneration(address)'], + '0x125b8f06': ['isInNextGeneration()'], + '0xd1734eac': ['isInNextGeneration(address)'], + '0x1ae460e5': ['isInPool()'], + '0x8baced64': ['isInPool(address)'], + '0x23306ed6': ['getMinimumBond()'], + '0x3cbfed74': ['getBondBalance()'], + '0x33613cbe': ['getBondBalance(address)'], + '0x741b3c39': ['depositBond()'], + '0xae6c0b03': ['canWithdrawBond(uint256)'], + '0x157ad5a1': ['canWithdrawBond(address,uint256)'], + '0xc3daab96': ['withdrawBond(uint256)'], + '0xeb947f19': ['ExampleResourcePool()'], + '0x2e817963': ['set_sdl(address)'], + '0x8757a2cd': ['test_depth(uint256,uint256)'], + '0x4afce471': ['test_requires_depth(uint16)'], + '0x135217e7': ['requires_depth()'], + '0x05d2f92a': ['check_depth(address,uint256)'], + '0x8e9ccd04': ['computeIndexId(address,bytes)'], + '0xfa80918b': ['computeNodeId(bytes,bytes)'], + '0x996a4be3': ['uintToBytes(uint256,uint256)'], + '0xcc8af0fe': ['bytesToUInt(bytes,bytes)'], + '0xa6f0e577': ['isLeapYear(uint16)'], + '0xb1999937': ['leapYearsBefore(uint256)'], + '0xb238ad0e': ['getDaysInMonth(uint8,uint16)'], + '0xf97d0591': ['parseTimestamp(uint256)'], + '0x92d66313': ['getYear(uint256)'], + '0xa324ad24': ['getMonth(uint256)'], + '0x65c72840': ['getDay(uint256)'], + '0x3e239e1a': ['getHour(uint256)'], + '0xfa93f883': ['getMinute(uint256)'], + '0x8aa001fc': ['getSecond(uint256)'], + '0x4ac1ad78': ['getWeekday(uint256)'], + '0x8c8d98a0': ['toTimestamp(uint16,uint8,uint8)'], + '0x7f791833': ['toTimestamp(uint16,uint8,uint8,uint8)'], + '0x62ba9687': ['toTimestamp(uint16,uint8,uint8,uint8,uint8)'], + '0x9054bdec': ['toTimestamp(uint16,uint8,uint8,uint8,uint8,uint8)'], + '0x136af582': ['next(bytes,bytes,bytes,bytes,bytes,bytes,bytes)'], + '0xa3ec5616': ['next(bytes,bytes,bytes,bytes,bytes,bytes,bytes,uint256)'], + '0x96f0aa8f': ['findNextSecond(uint256,bytes)'], + '0xc60ce271': ['findNextMinute(uint256,bytes)'], + '0x2f7f3ecf': ['findNextHour(uint256,bytes)'], + '0xdcaa5620': ['findNextWeekday(uint256,bytes)'], + '0x54d9d6f8': ['findNextDay(uint256,bytes)'], + '0xb245fc92': ['findNextMonth(uint256,bytes)'], + '0x8e280dce': ['findNextYear(uint256,bytes)'], + '0x7dc5cd32': ['_patternToNumber(bytes)'], + '0x7fc90182': ['Pool(uint256)'], + '0x96ff7e97': ['requestIdentity()'], + '0x998446a8': ['acceptRequest(uint256,bytes)'], + '0x2d7788db': ['rejectRequest(uint256)'], + '0x58e29e17': ['initiateProof()'], + '0x14cabddb': ['joinProof(uint256)'], + '0xae169a50': ['claimReward(uint256)'], + '0xc944a38e': ['CharlyLifeLog(string,int256)'], + '0xb60e72cc': ['log(string,uint256)'], + '0x09a399a7': ['personAdd(string,int256,int256,string)'], + '0x0af658ca': ['personUpdateActivity(uint256,bool)'], + '0x4a9b3f95': ['personUpdateName(uint256,string)'], + '0x0ce3151c': ['personUpdateRelation(uint256,string)'], + '0x61591a7c': ['personUpdateDOB(uint256,int256)'], + '0x98866c1a': ['personUpdateDOD(uint256,int256)'], + '0x524fa7b9': ['whitelistAdd(address)'], + '0xa932ed0d': ['whitelistRemove(address)'], + '0x2e1a7d4d': ['withdraw(uint256)'], + '0xed88c68e': ['donate()'], + '0x33298e25': ['invoke(uint256,uint256)'], + '0x2b30d2b8': ['invoke(uint256)'], + '0xc258ff74': ['List()'], + '0x959ac484': ['push(uint256)'], + '0x2b16b56a': ['setIndex(uint256,uint256)'], + '0x1f7b6d32': ['length()'], + '0x8e7cb6e1': ['getIndex(uint256)'], + '0x57dc9760': ['DaoChallenge()'], + '0x083b2732': ['callback()'], + '0x6d4ce63c': ['get()'], + '0xd09de08a': ['increment()'], + '0xc3ee6311': ['lockAndCall(string)'], + '0xe94acf0e': ['TinyRouter(address)'], + '0x39e525f9': ['resolveCallback(uint256)'], + '0x302d350e': ['firstChainedCallback(uint256)'], + '0x539e2bfb': ['secondChainedCallback(uint256)'], + '0x4f896d4f': ['resolve(uint256)'], + '0x9935935f': ['setResolveHandler(bytes,address)'], + '0x5dc77e26': ['andThen(string,address)'], + '0x7c45ef6c': ['stringToSig(string,string)'], + '0xbf8783e0': ['callAndGetReturn(address,bytes,uint256)'], + '0x9ed93318': ['create(address)'], + '0xd7bb99ba': ['contribute()'], + '0xc98165b6': ['createTarget()'], + '0x6493d7fc': ['CircuitBreaker(address,address,uint256,uint256)'], + '0xb7760c8f': ['transfer(uint256,address)'], + '0xa83627de': ['updatePeriod()'], + '0x8e5d97a2': ['releasePendingTransfer(uint256)'], + '0x66e5cb50': ['stopTransfer(uint256)'], + '0x75862df4': ['TokenWithEStop(address)'], + '0x63a599a4': ['emergencyStop()'], + '0xd0e30db0': ['deposit()'], + '0xe2faf044': ['createDAO(address,uint256,uint256,uint256)'], + '0xcc25decd': [ + 'SampleOffer(address,bytes,uint256,uint256,uint256,uint256,uint256)' + ], + '0x3535cd52': ['setDailyCosts(uint256)'], + '0xd4065763': ['returnRemainingMoney()'], + '0x9b29cb23': ['getDailyPayment()'], + '0xd002462b': ['setDeploymentFee(uint256)'], + '0xea25f24a': ['TokenCreation(uint256,uint256,address)'], + '0x704b6c02': ['setAdmin(address)'], + '0x29090202': ['Resolver(address)'], + '0xd393c871': ['register(string,address,uint256)'], + '0x18b31f94': ['registerLengthFunction(string,string,address)'], + '0x32b12eac': ['setFallback(address)'], + '0xc3b2556d': ['lookup(bytes)'], + '0xdc3f65d3': ['createdByMe()'], + '0x05215b2f': ['createStandardToken(uint256)'], + '0x7102c138': ['Standard_Token(uint256)'], + '0xfe01f1ff': ['TokenTester()'], + '0xa30b5c69': ['AttributeModel()'], + '0xc27d7721': ['create(uint256[101][])'], + '0x67f12ecf': ['validate(address,uint256,uint256[101][])'], + '0x63e38ff3': ['id_for_nym(uint256)'], + '0xcabfb934': ['replace(address)'], + '0xbd119967': ['add_rating(uint256,uint256)'], + '0x8f70009d': ['id_for_address(address,address)'], + '0x3b107682': ['DualIndex()'], + '0x43b0e8df': ['set(uint256,uint256,uint256)'], + '0xf0350c04': ['transfer_ownership(address)'], + '0xb4b9d1f1': ['lookup(uint256,uint256)'], + '0x272cda88': ['EternalDB()'], + '0x06661abd': ['count()'], + '0xcccf7a8e': ['has(uint256)'], + '0x9c851ebc': ['new_entry()'], + '0x505fb46c': ['add(uint256,uint256,uint256)'], + '0x25010816': ['get_length(uint256,uint256)'], + '0x58e59c32': ['get_entry(uint256,uint256,uint256)'], + '0x89029d8c': ['get_all(uint256,uint256)'], + '0x41ee903e': ['clear(uint256,uint256)'], + '0x1a10cfc3': ['delete_entry(uint256,uint256,uint256)'], + '0xf739ed4c': ['id_for_user_version(uint256,uint256)'], + '0x23cd7cd5': ['Model()'], + '0x3fda1281': ['get_keys()'], + '0x41d31feb': ['get_read_only_keys()'], + '0x582ca57b': ['get_associations()'], + '0x8ee21b8e': ['get_default_keys()'], + '0xeb121e2f': ['update(uint256,uint256[101][])'], + '0x595da94d': ['has_owners(uint256)'], + '0xd716222c': ['is_owner(uint256,address)'], + '0xb56b2627': ['add_owner(uint256,address)'], + '0x9d118770': ['destroy(uint256)'], + '0xdb6fcf01': ['is_destroyed(uint256)'], + '0xebd83378': ['get_blocks_for(uint256)'], + '0x49fb2dc5': ['add_to_association(uint256,uint256,uint256)'], + '0xe2deaa81': ['set_reference(uint256,uint256,uint256)'], + '0xf99ff4df': ['paged(uint256,uint256)'], + '0xa60bbcd3': ['ModelCoordinator()'], + '0x702fc7da': ['ReviewModel()'], + '0xe299beb3': ['SimpleIndex()'], + '0x1ab06ee5': ['set(uint256,uint256)'], + '0x0a874df6': ['lookup(uint256)'], + '0x39246d75': ['VersionModel()'], + '0x5c8a1053': ['extend(string)'], + '0x43d726d6': ['close()'], + '0x00ce2057': ['triggerPayment()'], + '0x4a3b0eec': ['authorizeOpen(uint256,bool,string)'], + '0xfdc4b338': ['authorizeExtension(uint256,bool,string)'], + '0x59d96db5': ['terminate(uint256,string)'], + '0x8ae475a9': ['notorize(string)'], + '0xb5d1990d': ['numRecords()'], + '0x4fb2e45d': ['transferOwner(address)'], + '0x29c08ba2': ['payPremium()'], + '0x0220a5b4': ['terminate(string)'], + '0x83f95f13': ['openClaim(string)'], + '0x1c1b8772': ['update(address)'], + '0xe6cb9013': ['safeAdd(uint256,uint256)'], + '0xa293d1e8': ['safeSub(uint256,uint256)'], + '0x6241bfd1': ['Token(uint256)'], + '0x0aa7881a': ['MintableToken(int256,uint256)'], + '0x27e056a5': ['addMinter(int256,address)'], + '0xad2fea7c': ['removeMinter(int256,address)'], + '0x1f3a3a53': ['mint(int256,uint256)'], + '0x2c7c4549': ['PurchasableToken(uint256)'], + '0x6a61e5fc': ['setTokenPrice(uint256)'], + '0xefef39a1': ['purchase(uint256)'], + '0x2f30283e': ['testSomething()'], + '0x3e5087cc': ['testBasicThing()'], + '0x4bbb216c': ['_target(address)'], + '0xa163a624': ['Test()'], + '0xa9cc4718': ['fail()'], + '0x0c9fd581': ['assertTrue(bool)'], + '0x5eb3f639': ['assertTrue(bool,bytes)'], + '0xa5982885': ['assertFalse(bool)'], + '0x16cb9a01': ['assertFalse(bool,bytes)'], + '0xf578fd85': ['assertEq0(bytes,bytes)'], + '0x7fa22001': ['assertEq0(bytes,bytes,bytes)'], + '0xd1af8a5a': ['LinkerExample()'], + '0x8af784dc': ['expectEventsExact(address)'], + '0xd38159b8': ['testPass()'], + '0x04d91c6a': ['testFail()'], + '0xc813c30e': ['testThrowSomething()'], + '0xfac34ff6': ['throwFoo()'], + '0x7fcf3a2f': ['throwFooBar()'], + '0x0db73c72': ['noevent()'], + '0x4f9d719e': ['testEvent()'], + '0x8bbb5af7': ['test1Fails()'], + '0x88a1e895': ['test2Fails()'], + '0xfdc193a4': ['test3Fails()'], + '0xdbecc372': ['Example(uint256)'], + '0x934bc29d': ['exampleFunction(uint256)'], + '0x3c67c51e': ['testLogs()'], + '0xe44d3084': ['testFailure()'], + '0x94bcdb4c': ['Example2()'], + '0xa677fbd9': ['example2Func()'], + '0x773c84ee': ['exec(address,bytes,uint256,uint256)'], + '0xf3541901': ['execute(address,bytes,uint256,uint256)'], + '0x1b437d0c': ['compareLastCalldata(bytes)'], + '0xdcfa9cc0': ['testProxyCall()'], + '0x2d2c44f2': ['Vault()'], + '0x0b6142fc': ['breach()'], + '0x6c050eae': ['look()'], + '0x04a2b2c2': ['testOwnerCanBreach()'], + '0x94a1710d': ['testNonOwnerCantBreach()'], + '0xb4c4e005': ['testTransferToAcceptAuthority()'], + '0xe17e1274': ['testTransferToRejectAuthority()'], + '0x2b1071c9': ['testTransferToNullAuthority()'], + '0xf0f967e8': ['canCall(address,address,bytes)'], + '0xe6d95eb8': ['DSAuthorized()'], + '0x57e6c2f4': ['isAuthorized()'], + '0xe2b178a0': ['getAuthority()'], + '0x6cd22eaf': ['updateAuthority(address,bool)'], + '0xfe9fbb80': ['isAuthorized(address)'], + '0x3c716e08': ['updateAuthority(address)'], + '0xed62cf1f': ['setCanCall(address,address,bytes,bool)'], + '0xc37e8cb2': ['testExportAuthorized()'], + '0xb870ecbb': ['testNormalWhitelistAdd()'], + '0x19f02ceb': ['set(address,address,uint256)'], + '0xd81e8423': ['get(address,address)'], + '0xf639365d': ['testSetGet()'], + '0x8b95ec0c': ['testAddBalance()'], + '0x6dbe31eb': ['testSubBalance()'], + '0x65f27bea': ['testSubBalanceFailsBelowZero()'], + '0xce220ecf': ['testAddBalanceFailsAboveOverflow()'], + '0x1bf20668': ['testAdminTransfer()'], + '0xd6d7d525': ['get(bytes)'], + '0xa18c751e': ['set(bytes,bytes)'], + '0x73e1743a': ['buildDSBasicAuthority()'], + '0x7d4cf602': ['buildDSBalanceDB()'], + '0xacf4280c': ['buildDSApprovalDB()'], + '0x089e0ad0': ['buildDSMap()'], + '0x2bed55b0': ['buildDSEasyMultisig(uint256,uint256,uint256)'], + '0x3647b87a': ['buildFactory()'], + '0x9e2262f5': ['testCreateCostData()'], + '0x386fcda8': ['testCreateCostToken()'], + '0x4e6ba0a9': ['testCreateCostMultisig()'], + '0x7c05caf3': ['testCreateCostAuth()'], + '0x5b067cce': ['testCreateCostMain()'], + '0xb06eb03f': ['DSEasyMultisig(uint256,uint256,uint256)'], + '0xca6d56dc': ['addMember(address)'], + '0xa230c524': ['isMember(address)'], + '0xf6d5959b': ['getActionStatus(uint256)'], + '0xff1b4341': ['easyPropose(address,uint256,uint256)'], + '0x268bb78e': ['propose(address,bytes,uint256,uint256)'], + '0xba0179b5': ['confirm(uint256)'], + '0xed684cc6': ['trigger(uint256)'], + '0xa6b206bf': ['doSomething(uint256)'], + '0xbca86986': ['testSetup()'], + '0x11d12402': ['testEasyPropose()'], + '0x246c02e6': ['check_depth(uint16)'], + '0x44602a7d': ['testFallbackReturn()'], + '0xbe45fd62': ['transfer(address,uint256,bytes)'], + '0x1b00fe51': ['testHypothesis()'], + '0xf06186c7': ['testReality()'], + '0xb09bc3bf': ['try_to_get()'], + '0xdabf7ec4': ['helper(uint256)'], + '0x8040cac4': ['testOverflow()'], + '0x828d671c': ['dyn_sig()'], + '0xe2f8feb2': ['internal_tester(int256)'], + '0xe0ad411d': ['assets(bytes)'], + '0x18178358': ['poke()'], + '0x6b1feeeb': ['get_my_sig()'], + '0xd57a12f5': ['testCheckSigs()'], + '0x60b431a4': ['testGetSig()'], + '0x189c94ae': ['testFallbackStaticSig()'], + '0x22017c5f': ['DSTokenBase(uint256)'], + '0xbeabacc8': ['transfer(address,address,uint256)'], + '0x15dacbea': ['transferFrom(address,address,address,uint256)'], + '0xe1f21c67': ['approve(address,address,uint256)'], + '0x003074ff': ['getFrontend()'], + '0xc971442c': ['getDBs()'], + '0x4956eaf0': ['deploy(address,uint256)'], + '0xf6c5c80d': ['cleanUp()'], + '0xb17b94c1': ['testSystem()'], + '0xe23941bc': ['testDepositWithdraw()'], + '0x1334a5e2': ['eventCallback(uint8,address,address,uint256)'], + '0x3018205f': ['getController()'], + '0x7fe1dc7e': ['getToken(bytes)'], + '0xef3a6031': ['testBaseToken()'], + '0xb085b9a5': ['Example()'], + '0x55241077': ['setValue(uint256)'], + '0x20965255': ['getValue()'], + '0x29d017b5': ['TestWithConstructor(address,uint256[])'], + '0x4b64e492': ['execute(address)'], + '0xf4b103d4': ['SimpleStorage(uint256)'], + '0xfc0c546a': ['token()'], + '0x90b98a11': ['sendCoin(address,uint256)'], + '0x01cb3b20': ['checkGoalReached()'], + '0xc0d2834b': ['DataSource()'], + '0x4b0697e4': ['Manager(address)'], + '0x044215c6': ['token(uint256)'], + '0x299e6b07': ['Wallet(address)'], + '0x93423e9c': ['getAccountBalance(address)'], + '0xbe999705': ['addFunds(uint256)'], + '0xbc4b3365': ['addFunds(address,uint256)'], + '0xa1a66e56': ['deductFunds(uint256)'], + '0x8d72a473': ['deductFunds(address,uint256)'], + '0x08aba5aa': ['setAccountBalance(uint256)'], + '0x46ddb7db': ['setAccountBalance(address,uint256)'], + '0xdb4cacec': ['Other()'], + '0x84a7b223': ['Canary(address)'], + '0x5c634241': ['CanaryV6()'], + '0xb5d3a379': ['CanaryTestnet()'], + '0x41868769': ['CallAborted(address,bytes)'], + '0x6560a307': ['suggestedGas()'], + '0xeec2b628': ['beforeExecute(address)'], + '0x980e8c81': [ + 'FutureBlockCall(address,uint256,uint8,address,bytes,uint256,uint256,uint256)' + ], + '0x08f235ec': ['getDefaultPayment()'], + '0x21bacf28': ['getDefaultFee()'], + '0x75c589a0': ['getMinimumCallCost()'], + '0x6822abae': ['getMinimumCallCost(uint256)'], + '0x2635f4de': ['registerLibrary(bytes,address)'], + '0xc5ae6e0e': ['Kernal()'], + '0x2030f721': ['num_objects()'], + '0xc4bd8ebc': ['num_monsters()'], + '0xc13afa91': ['object_locations(uint256)'], + '0x1d5a9f3f': ['object_types(uint256)'], + '0xc0576b73': ['monsters(uint256)'], + '0xc368109c': ['monster_hp(uint256)'], + '0xa01bc729': ['monster_attack(uint256)'], + '0x75160a20': ['pay_royalties()'], + '0x26121ff0': ['f()'], + '0xaef99eef': ['Game()'], + '0xe604cf9f': ['get_all_squares()'], + '0xbe600276': ['move(uint16)'], + '0xf651bf44': ['move_to(uint16)'], + '0xa5f3c23b': ['add(int256,int256)'], + '0x37c390e3': ['allow_move(uint16)'], + '0xdcf537b1': ['multiply7(int256)'], + '0x16216f39': ['return13()'], + '0x6ed7c013': ['move_monsters()'], + '0xcec7260b': ['move_monster(uint16,uint16)'], + '0xecb98714': ['random_damage(uint256)'], + '0x2d8c1c35': ['level_up()'], + '0xf504e0da': ['load_level(uint16)'], + '0x99753de7': ['clear_level()'], + '0xde5d953a': ['logSingleIndex(bytes,bytes,uint256)'], + '0xb409da05': ['logDoubleIndex(bytes,bytes,bytes,uint256)'], + '0xb29a0308': ['logAnonymous(bytes,bytes,bytes,uint256)'], + '0x5f515226': ['checkBalance(address)'], + '0x7eaef50c': ['over()'], + '0x12c8052f': ['won()'], + '0x21970c0c': ['pay_royalty()'], + '0x4c1b2446': ['transmitInteger(address,bytes,bytes,uint256,uint16)'], + '0x42909a9e': ['create_game()'], + '0xe54d4051': ['receiveInteger(bytes,uint256,uint16)'], + '0x8365172c': ['num_levels()'], + '0x3ced842b': ['make_offer()'], + '0x48db5f89': ['player()'], + '0x6896fabf': ['getAccountBalance()'], + '0x5b86914d': ['bet_value()'], + '0x6e8dad74': ['retrieveAccountBalance(bytes,bytes)'], + '0x6d705ebb': ['register(address,uint256)'], + '0x46b5e202': ['set_num_levels(uint256,uint256)'], + '0xbfad16f4': ['new_offer(uint256,uint256)'], + '0x97d47a60': ['registerAccountant(bytes,address)'], + '0x19b05f49': ['accept(uint256)'], + '0xdf3c8620': ['num_challenges()'], + '0xc3d0a564': ['getAccountBalance(bytes)'], + '0xf249cf19': ['get_all_challenges()'], + '0x340f5e4e': ['get_all_num_levels()'], + '0x407cfe5e': ['get_all_players()'], + '0xd1a8d447': ['get_all_bet_values()'], + '0x7140bdf3': ['get_all_best_offers()'], + '0x6677febe': ['get_all_accepted()'], + '0x5718b994': ['checkEvent(address,bytes,bytes,uint256)'], + '0xf51cbc72': ['Level()'], + '0x7cb97b2b': ['set_owner(address)'], + '0x7212b67e': ['add_potion(uint16)'], + '0xdd729530': ['add_shield(uint16)'], + '0xcc2c5453': ['add_sword(uint16)'], + '0xf3c37bd5': ['Verifier(address,uint256,uint8)'], + '0xf262de8c': ['add_staircase(uint16)'], + '0x62c335c1': ['checkCallback(address,uint256,bytes,bytes)'], + '0xe97b2190': ['add_wall(uint16)'], + '0x37a6b9f8': ['recordCallback(address,uint256,bytes,bytes)'], + '0x79216f5f': ['add_monster(uint16,uint16,uint16)'], + '0x52efea6e': ['clear()'], + '0x4bb278f3': ['finalize()'], + '0xb651cbaf': ['add_level(address,bytes)'], + '0xc985c221': ['get_all_levels()'], + '0x309424fe': ['get_all_names()'], + '0x7365870b': ['bet(uint256)'], + '0xdf25ee23': ['getIndexId(address,bytes)'], + '0x8963dab4': ['getNodeId(bytes,bytes)'], + '0x0c5c2ca3': ['getIndexName(bytes)'], + '0x337c1e28': ['getIndexRoot(bytes)'], + '0xf64fca2e': ['getNodeId(bytes)'], + '0xaa272d4b': ['getNodeIndexId(bytes)'], + '0x5ca1c5a0': ['getNodeValue(bytes)'], + '0x662dbe96': ['getNodeHeight(bytes)'], + '0x3517a740': ['getNodeParent(bytes)'], + '0xc1b056b0': ['getNodeLeftChild(bytes)'], + '0x4296a9cb': ['getNodeRightChild(bytes)'], + '0xb0aab296': ['getNextNode(bytes)'], + '0x1b370abb': ['getPreviousNode(bytes)'], + '0x3943807b': ['insert(bytes,bytes,int256)'], + '0xbea124a6': ['query(bytes,bytes,int256)'], + '0xb7bae9b7': ['exists(bytes,bytes)'], + '0x69573648': ['remove(bytes,bytes)'], + '0xb7e24979': ['addThing(bytes)'], + '0xe51ff1fc': ['iterateOverThings()'], + '0x69307c80': ['rotateBits(bytes,int256)'], + '0x6506b623': ['rotateBitsLeft(bytes,uint256)'], + '0x109df68e': ['rotateBitsRight(bytes,uint256)'], + '0xc02f081a': ['shiftBits(bytes,int256)'], + '0x5e07f240': ['shiftBitsLeft(bytes,uint256)'], + '0xff27c476': ['shiftBitsRight(bytes,uint256)'], + '0x15e33901': ['digest(bytes,uint256)'], + '0x41c0e1b5': ['kill()'], + '0x780900dc': ['create(uint256)'], + '0xa1e4d3c2': ['MembershipRoster()'], + '0x76d690bb': ['BountyList()'], + '0x0b1ca49a': ['removeMember(address)'], + '0xee2af3fb': ['set_factory(address)'], + '0x5fb64fd6': ['checkMembership(address)'], + '0x10c4e8b0': ['all()'], + '0x85654c9c': ['setMembershipRoster(address)'], + '0xeb95b7d5': ['Bounty(address,address)'], + '0x0b7e9c44': ['payout(address)'], + '0x92e9fd5e': ['ColdWallet(address,address)'], + '0x8a4fb16a': ['getWithdrawal(uint256)'], + '0xd845a4b3': ['request(uint256)'], + '0xfe0d94c1': ['execute(uint256)'], + '0xf3b50c04': ['rescind()'], + '0x49c15bd9': ['Purchase()'], + '0x35a063b4': ['abort()'], + '0xd6960697': ['confirmPurchase()'], + '0x73fac6f0': ['confirmReceived()'], + '0xda0774ad': ['getCallFeeScalar(uint256,uint256)'], + '0x4c33fe94': ['cancel(address)'], + '0xc032dc30': ['execute(uint256,address)'], + '0x6a704d7b': ['AddedToGeneration(address,uint256)'], + '0xf1173928': ['RemovedFromGeneration(address,uint256)'], + '0x345006b6': ['getGenerationForCall(address)'], + '0xb3559460': ['getGenerationSize(uint256)'], + '0xa6c01cfd': ['isInGeneration(uint256)'], + '0x04dd69fa': ['getGenerationIdForCall(address)'], + '0x5a8dd79f': ['getDesignatedCaller(address,uint256)'], + '0xdc75f2db': ['multiowned(address[],uint256)'], + '0x0b467b9b': ['revoke(bytes)'], + '0xf00d4b5d': ['changeOwner(address,address)'], + '0x7065cb48': ['addOwner(address)'], + '0x173825d9': ['removeOwner(address)'], + '0xba51a6df': ['changeRequirement(uint256)'], + '0x2f54bf6e': ['isOwner(address)'], + '0x3b49a77b': ['hasConfirmed(bytes,address)'], + '0xe88b8ac6': ['confirmAndCheck(bytes)'], + '0xc1812b15': ['reorganizeOwners()'], + '0x5f6a1301': ['clearPending()'], + '0xae99847b': ['daylimit(uint256)'], + '0xb20d30a9': ['setDailyLimit(uint256)'], + '0x5c52c2f5': ['resetSpentToday()'], + '0x180aadb7': ['underLimit(uint256)'], + '0xb74e452b': ['today()'], + '0xb61d27f6': ['execute(address,uint256,bytes)'], + '0xf2ddc772': ['confirm(bytes)'], + '0xc4ff3614': ['Wallet(address[],uint256,uint256)'], + '0xcbf0b0c0': ['kill(address)'], + '0xe854dfb4': ['Order(address,uint256,uint256)'], + '0x4c0bcfe5': ['getTransferableBalance(address)'], + '0x8f367001': ['numTokensAbleToPurchase()'], + '0x370ec1c5': ['_fillOrder(address,uint256)'], + '0xd9feeeb6': ['fillMyOrder(uint256)'], + '0xfcc6b5d5': ['fillTheirOrder(address)'], + '0x39f4debc': ['fillOrderAuto()'], + '0x9a1b420b': ['OraclizeAddrResolver()'], + '0xd1d80fdf': ['setAddr(address)'], + '0x0e1ca8a5': ['Oraclize()'], + '0xa2ec191a': ['addDSource(string,uint256)'], + '0x62b3b833': ['createCoupon(string)'], + '0xa8239d0b': ['getPrice(string,address)'], + '0xbf1fe420': ['setGasPrice(uint256)'], + '0x8579cbde': ['getPrice(string,uint256,address)'], + '0xde4b3262': ['setBasePrice(uint256)'], + '0x7d242ae5': ['setBasePrice(uint256,bytes)'], + '0x81ade307': ['query(string,string)'], + '0x45362978': ['query1(string,string)'], + '0xe839e65e': ['query2(string,string,string)'], + '0x23dc42e7': ['query1(uint256,string,string)'], + '0xae815843': ['query(uint256,string,string,uint256)'], + '0x5c242c59': ['query1(uint256,string,string,uint256)'], + '0x7e1c4205': ['query2(uint256,string,string,string,uint256)'], + '0x75700437': ['query1_withGasLimit(uint256,string,string,uint256)'], + '0xb303dcbd': ['Owned()'], + '0x32e7c5bf': ['B()'], + '0xc6888fa1': ['multiply(uint256)'], + '0xf8a8fd6d': ['test()'], + '0x78710d37': ['seven()'], + '0xe1bedf2a': ['AlarmTester(address)'], + '0xb29f0835': ['doIt()'], + '0x185061da': ['undoIt()'], + '0xdd012a15': ['setIt(uint256)'], + '0x22beb9b9': ['scheduleDoIt(uint256)'], + '0xd6b44859': ['scheduleUndoIt(uint256)'], + '0x245a03ec': ['scheduleSetIt(uint256,uint256)'], + '0x7429c086': ['repeat()'], + '0x553cc48d': ['Player(string)'], + '0x37b7bf11': ['Tile(int256,int256)'], + '0x2d67bb91': ['World()'], + '0xead710c4': ['greet(string)'], + '0x0f4cf692': ['numMessages()'], + '0xc633084f': ['sendGreeting(address,string)'], + '0xc6e1c178': ['TheLuckyOne(bytes)'], + '0xf18d20be': ['adminWithdraw()'], + '0x4faa2d54': ['getTimeElapsed()'], + '0xe8223468': ['sha3clone(bytes)'], + '0xa59d6986': ['recoverLostFunds()'], + '0xc535165f': ['revealAndPayout(bytes,bytes)'], + '0xf1eae25c': ['mortal()'], + '0xfaf27bca': ['greeter(string)'], + '0xcfae3217': ['greet()'], + '0xb51c4f96': ['getCodeSize(address)'], + '0x95978868': ['strConcat(string,string,string,string,string)'], + '0x45e965cd': ['strConcat(string,string,string,string)'], + '0x4112987c': ['strConcat(string,string,string)'], + '0xf5c98aff': ['GreeterB(bytes)'], + '0x3bc5de30': ['getData()'], + '0x9c1193ea': ['GreeterA(bytes)'], + '0x905e6e42': ['JSON_Test()'], + '0x1e26fd33': ['setBool(bool)'], + '0x9a19a953': ['setInt8(int8)'], + '0x4dfd1b02': ['setUint8(int8,uint8)'], + '0xa53b1c1e': ['setInt256(int256)'], + '0xec21a913': ['setUint256(int256,uint256)'], + '0x6cc5fdaa': ['setBytes32(bytes,bytes)'], + '0x12a7b914': ['getBool()'], + '0x57cb2fc4': ['getInt8()'], + '0x4a41e045': ['getUint8(int8)'], + '0xf5b53e17': ['getInt256()'], + '0xed180443': ['getUint256(int256)'], + '0x1f903037': ['getBytes32()'], + '0x65538c73': ['fireEventLog0()'], + '0xa6780857': ['fireEventLog0Anonym()'], + '0xb61c0503': ['fireEventLog1()'], + '0x4e7ad367': ['fireEventLog1Anonym()'], + '0x102accc1': ['fireEventLog2()'], + '0x76bc21d9': ['fireEventLog2Anonym()'], + '0xf38b0600': ['fireEventLog3()'], + '0xe8beef5b': ['fireEventLog3Anonym()'], + '0xfd408767': ['fireEventLog4()'], + '0x9dc2c8f5': ['fireEventLog4Anonym()'], + '0x2839e928': ['ackermann(uint256,uint256)'], + '0x61047ff4': ['fibonacci(uint256)'], + '0xdbbdf083': ['register(uint256,address)'], + '0xa02b161e': ['unregister(uint256)'], + '0x5fd4b08a': ['getName(address)'], + '0x1c4e6cd0': ['NameReg()'], + '0xe79a198f': ['unregister()'], + '0xf5c57382': ['nameOf(address)'], + '0xc47cf5de': ['getAddress(bytes)'], + '0x82fbdc9c': ['register(bytes)'], + '0x034cb28e': ['addressOf(address,bytes)'], + '0xf004b12b': ['CrowdFund(uint256,uint256,address)'], + '0x9bb01b5f': ['ElcoinDb(address)'], + '0x893d20e8': ['getOwner()'], + '0xab470f05': ['getCaller()'], + '0xbeb92f55': ['setCaller(address)'], + '0xf3125a1f': ['deposit(address,uint256,bytes,uint256)'], + '0x9483e91a': ['withdraw(address,uint256,bytes,uint256)'], + '0x3b343a13': ['getNodeAddress(bytes)'], + '0x7bfaad96': ['addNode(bytes,address)'], + '0xca3b5c91': ['hasRelation(bytes,bytes,address)'], + '0xba45b0b8': ['transfer(address,address)'], + '0xf8b71c64': ['rewardTo(address,uint256)'], + '0xfbf1f78a': ['unapprove(address)'], + '0x5184ffc9': ['setAmbiAddress(address,bytes)'], + '0xa7f43779': ['remove()'], + '0x444dd6f3': ['Elcoin()'], + '0x4a606c53': ['_db()'], + '0x9b9d0364': ['_setFeeStructure(uint256,uint256,uint256)'], + '0x99a5d747': ['calculateFee(uint256)'], + '0x63f80de3': ['issueCoin(address,uint256,uint256)'], + '0x88d695b2': ['batchTransfer(address[],uint256[])'], + '0xaa64c43b': ['transferPool(address,address,uint256)'], + '0xc71cbcf3': ['recoverAccount(address,address)'], + '0xb2855b4f': ['setFeeAddr(address)'], + '0x5b65b9ab': ['setFee(uint256,uint256,uint256)'], + '0x3f2f1596': ['setupTreasury(address,uint256)'], + '0x24c65f35': ['updateRefundGas()'], + '0x8f0c724c': ['setOperationsCallGas(uint256)'], + '0x23df9df5': ['_refund(uint256)'], + '0xd449ce7c': ['Administered()'], + '0xa925d85e': ['Exchange(address,address)'], + '0xf34c7010': ['commitSecurity(address,uint256,uint256)'], + '0x6d09e2ec': ['commitCurrency(address,uint256,uint256)'], + '0x144267e0': ['refundSecurity(address,uint256,uint256)'], + '0xc9cfac55': ['refundCurrency(address,uint256,uint256)'], + '0xa5b1e13d': ['settle(address,address,uint256,uint256)'], + '0x1d8ae626': ['Security(string,string)'], + '0xc74e907b': ['commit(address,uint256,uint256)'], + '0x60708ae3': ['issueAndCommit(address,address,uint256,uint256)'], + '0x68f2ab8e': ['Currency(string,string)'], + '0xb21bce4c': ['vote(bytes,bool)'], + '0x3b143184': ['Congress(uint256,uint256,int256,address)'], + '0x9644fcbd': ['changeMembership(address,bool,string)'], + '0xbcca1fd3': ['changeVotingRules(uint256,uint256,int256)'], + '0xb1050da5': ['newProposal(address,uint256,string,bytes)'], + '0xd3c0715b': ['vote(uint256,bool,string)'], + '0xbcc6092a': ['MyEtherBank()'], + '0xd917deb5': ['Donate()'], + '0xb774d3d7': ['BankOwner_GetDonationsBalance()'], + '0x07718a3b': ['BankOwner_WithdrawDonations()'], + '0x2dae9878': ['BankOwner_EnableConnectBankAccountToNewOwnerAddress()'], + '0x9be1fcee': ['BankOwner_DisableConnectBankAccountToNewOwnerAddress()'], + '0x32829a23': ['OpenBankAccount()'], + '0x25f3da52': ['GetBankAccountNumber()'], + '0xcf2e3efc': ['GetBankAccountBalance()'], + '0x9a9c9c53': ['DepositToBankAccount()'], + '0x62b24189': ['DepositToBankAccountFromDifferentAddress(uint32)'], + '0x13651124': ['WithdrawAmountFromBankAccount(uint256)'], + '0x85c7a953': ['WithdrawFullBalanceFromBankAccount()'], + '0x19663f7f': ['TransferAmountFromBankAccountToAddress(uint256,address)'], + '0xaf27c7b3': ['Security_HasPasswordSha3HashBeenAddedToBankAccount()'], + '0xb45c48dc': ['Security_AddPasswordSha3HashToBankAccount(bytes)'], + '0x766a3f2e': ['Security_ConnectBankAccountToNewOwnerAddress(uint32,string)'], + '0xf6232556': [ + 'Security_GetNumberOfAttemptsToConnectBankAccountToANewOwnerAddress()' + ], + '0x671fa0a0': ['Inscription(string)'], + '0xd6af9411': ['Rouleth()'], + '0x31119b4d': ['changeDeveloper(address)'], + '0xc87b36ed': ['disableBetting()'], + '0x5fa21f1f': ['enableBetting()'], + '0x63a8dac2': [ + 'changeSettings(uint256,uint256,uint256,uint8,uint256,uint256,uint8,uint8)' + ], + '0x2888f9d0': ['updateMaxBet()'], + '0x53f818d6': ['checkBetValue()'], + '0xb8cf14e7': ['updateStatusPlayer()'], + '0xb400d149': ['betOnNumber(uint8)'], + '0x5b7d47a9': ['betOnColor(bool,bool)'], + '0xadf54e0c': ['betOnLowHigh(bool,bool)'], + '0xb738169c': ['betOnOddEven(bool,bool)'], + '0xbfe8c107': ['betOnDozen(bool,bool,bool)'], + '0xe548cf13': ['betOnColumn(bool,bool,bool)'], + '0xd02bf162': ['spinTheWheel()'], + '0x403abbc7': ['updateFirstActiveGamble()'], + '0x021c309a': ['solveBet(address,uint8,bool,uint8)'], + '0x86269a88': ['checkBetNumber(uint8)'], + '0x57006864': ['checkBetParity(uint8)'], + '0xf80b3cfa': ['checkBetLowhigh(uint8)'], + '0xc1ae4044': ['checkBetColor(uint8)'], + '0xc124e2ea': ['checkBetDozen(uint8)'], + '0x06c1df7b': ['checkBetColumn(uint8)'], + '0xe8b5e51f': ['invest()'], + '0x2037fcbf': ['withdrawInvestment(uint256)'], + '0xb18c6847': ['manualUpdateBalances()'], + '0x6f3fe404': ['updateBalances()'], + '0x2c6b2c92': ['checkProfitLossSinceInvestorChange()'], + '0xf7ae9421': ['checkInvestorBalance(address)'], + '0x6ed43eb0': ['getInvestorList(uint256)'], + '0xf9e27106': ['investmentEntryCost()'], + '0x85b4bb53': ['getSettings()'], + '0xa0e2abf7': ['getFirstActiveGamble()'], + '0x942385eb': ['getPayroll()'], + '0x6e1b6bcc': ['checkMyBet(address)'], + '0xbcb3b5d2': ['getGamblesList(uint256)'], + '0x4e71e0c8': ['claimOwnership()'], + '0xb4d9cc3a': ['profitDisperser()'], + '0xc127c247': ['addMember(address,string)'], + '0x63deb2c5': ['changeMemberAddress(address)'], + '0x1c02708d': ['killContract()'], + '0xaacc5a17': ['getRandom()'], + '0x6103d915': ['Winners(uint256)'], + '0xd743ca38': ['newWinner(uint256,address,uint256,uint256,uint256)'], + '0x3e5fd9b5': ['dEthereumlotteryNet(address,address,bool,address)'], + '0x149c5066': ['ChanceOfWinning(uint256)'], + '0x860e9960': ['BetPriceLimit()'], + '0xe8930efd': ['Investors(address)'], + '0xc0819961': ['Invest()'], + '0xf9983a12': ['GetMyInvestmentBalance()'], + '0x7dee2cad': ['CancelMyInvestment()'], + '0x4247f52d': ['DoRoll()'], + '0x25209260': ['PrepareRoll(uint256)'], + '0x54738157': ['OwnerCloseContract()'], + '0xe9b93569': ['OwnerGetFee()'], + '0xe97db66e': ['setJackpot()'], + '0x9a7a7c11': ['makeRoll(uint256)'], + '0x414ceac0': ['investorAddFee(uint256)'], + '0x2f1927cb': ['prepareRoll(uint256,uint256,uint256)'], + '0x57764094': ['getRate(uint256)'], + '0x1dea0c57': ['getRealBet(uint256)'], + '0x3e0dfbdf': ['getInvestorByAddress(address)'], + '0xe5a27038': ['Pluton(uint256,string,uint8,string)'], + '0xcae9ca51': ['approveAndCall(address,uint256,bytes)'], + '0xc2412676': ['Token()'], + '0x3ccb7dc9': ['CrowdFund(uint256,uint256)'], + '0xe5225381': ['collect()'], + '0x3059ac30': ['Escrow(address,address)'], + '0x924c28c1': ['ContractInterface(address,address,address)'], + '0xdabc706e': ['getProposalCost()'], + '0x0380e2f3': ['getHashOfTheSignedDocument()'], + '0xd02a9889': ['getDateOfFirstPayment()'], + '0x938199a5': ['getDateOfLastPayment()'], + '0x708f29a6': ['getTotalPayments()'], + '0x270cfee1': ['getTokenAccount()'], + '0x00faf4dd': ['getTokenDivisor()'], + '0x8b863095': ['setContractorProposal(uint256,bytes)'], + '0x3e0d4f4a': ['ApproveContractorProposal()'], + '0xb7538f3e': ['ChangeClient(address)'], + '0x9ae4e388': ['ChangeClientTokenAccount(address,bool)'], + '0x9462eae5': ['ChangeContractor(address)'], + '0xea4af029': ['ConferenceCertification()'], + '0xd1f7a4e4': ['createCertificate(bytes)'], + '0x89eedf00': ['setPdfHash(bytes,bytes)'], + '0xbb3b8dca': ['getCertificateHash(bytes)'], + '0xc2def3b9': ['getOrganizer()'], + '0xb81e43fc': ['getEventName()'], + '0xe5dd90a5': ['HumanStandardToken(uint256,string,uint8,string)'], + '0x5d5bc4cb': ['BetOnRed()'], + '0x29d6f899': ['BetOnBlue()'], + '0xd0821b0e': ['bet(uint8)'], + '0x354d7e40': ['Payout()'], + '0x72c7c85a': ['minority()'], + '0x8f4ffcb1': ['receiveApproval(address,uint256,address,bytes)'], + '0x8a323b38': ['Contract(uint256,string,uint8,string)'], + '0x26745909': ['PRNG_Challenge()'], + '0xd2ef7398': ['challenge()'], + '0x76da5667': ['admin_kill()'], + '0xc2985578': ['foo()'], + '0x63bfe3d8': ['SkillBeatsLuck()'], + '0x478ae93c': ['playToWin(uint256)'], + '0x6a9d2afd': ['playToWinTest(uint256)'], + '0x793cd71e': ['cashOut()'], + '0x2530c905': ['rand(uint256)'], + '0x17db59a4': ['dEthereumlotteryNet(address,address,address)'], + '0xa0f029fc': ['ContractorInterface(address,address,address)'], + '0xf765088f': ['UpdateClientAddress(address)'], + '0x64e24f4b': ['UpdateClientTokenAccount(address)'], + '0xa36c8ec2': ['UpdateContractorAddress(address)'], + '0x84dac46e': ['Fucksign()'], + '0xfc1f2a70': ['Add(uint256,string,string)'], + '0xa87d942c': ['getCount()'], + '0xe3914699': ['dEthereumlotteryNetWinners(address)'], + '0x477bddaa': ['setContractAddress(address)'], + '0xc6ae3b57': ['dEthereumlotteryNet(address,address)'], + '0xe1376da2': ['updateFirstActiveGamble(uint256)'], + '0xd499555b': ['getFirstActiveDuel()'], + '0xf99fc046': ['dEthereumlotteryNet()'], + '0xc494f71a': ['LedgerFund(uint32,uint32,uint64,uint64)'], + '0xcdb6753b': ['setNav(uint32)'], + '0xc8691b2a': ['getHistory(uint256)'], + '0xbe1c766b': ['getLength()'], + '0x7cef6047': ['getNavHistory(uint256)'], + '0x9287c877': ['getNavLength()'], + '0xdd67a360': ['OrderLifeCycle()'], + '0x712ca0f8': ['getOrder(string)'], + '0xe3280126': ['addOrder(string,bool)'], + '0x1d8b70da': ['order_received(string)'], + '0x64265b1a': ['share_transfered(string)'], + '0x96ef7aa0': ['cash_transfered(string)'], + '0x13b2663b': ['cash_received(string)'], + '0xd052fbf6': ['getHistory(string,uint256)'], + '0x6981b5f4': ['getLength(string)'], + '0xbc9147a4': ['Foundation()'], + '0x6389654e': ['changeDailyWithdrawalLimit(uint256)'], + '0x12d00c2e': ['soloWithdraw(uint256)'], + '0xa4699cad': ['resetWithdrawls()'], + '0x3e476053': ['moveFunds(address,uint256)'], + '0xf5c8d71b': ['forceMove(address,address,uint256)'], + '0xfbae5e7d': ['Investors(uint256)'], + '0x1ceea715': ['GetMyInvestFee()'], + '0x1d2dbb22': ['CancelMyInvest()'], + '0xfee35ff8': ['newInvest(uint256,address,uint256)'], + '0x0ff0a4df': ['reFund()'], + '0x932db761': ['profitsFromBitnationDebitCard()'], + '0x79baa8a9': ['BasicIncome_CoFund()'], + '0x983ef725': ['getDifficulty(uint256)'], + '0xf00acc47': ['prepareRoll(uint256,uint256)'], + '0xf3c7d275': ['prenup(string,string,string,string,string,address,address)'], + '0x86a5ff97': ['changeStatus(string)'], + '0xffcce369': ['changeIPFSHash(string)'], + '0xb47d89ad': ['Details()'], + '0x24c9bf5e': ['Prizes()'], + '0xcee6ee38': ['aEthereumlotteryNet()'], + '0x91d8b14e': ['BuyTickets()'], + '0xd224118f': ['PrepareDraw()'], + '0xd4e78272': ['Draw()'], + '0xacc5a0dc': ['GetPrize()'], + '0xfea2920e': ['createNewDraw()'], + '0x350fbe2e': ['calcNextDrawTime()'], + '0x82f0d875': ['makeHash()'], + '0x206a44f3': ['getNum(bytes,uint256)'], + '0x5ed84aa6': ['getNymCenterAPIURL()'], + '0x4cdb48e4': ['isValidNym(address)'], + '0xf1320af2': ['exempt(address)'], + '0xf9e84395': ['unexempt(address)'], + '0xcc872b66': ['issue(uint256)'], + '0xdb006a75': ['redeem(uint256)'], + '0x879d46fd': ['DAOTrust(address,address,bytes,uint256,uint256,uint128)'], + '0xf7b89a3e': ['getTotalCosts()'], + '0x550538f6': ['getOneTimeCosts()'], + '0x0acc4382': ['getMinDailyWithdrawLimit()'], + '0xc988d70f': ['getDailyWithdrawLimit()'], + '0xd7ccc2c3': ['getLastPayment()'], + '0x7648c929': ['returnRemainingEther()'], + '0x6b256f57': ['DAOSecurity(address,address,bytes,uint256,uint256,uint128)'], + '0x293ffca3': ['AddressReg()'], + '0x63a9c3d7': ['verify(address)'], + '0x0d368fee': ['deverify(address)'], + '0xd173707d': ['hasPhysicalAddress(address)'], + '0x5f2e686d': ['Ethereum_eight_bagger()'], + '0x1437f9a3': ['Set_your_game_number(uint16)'], + '0xc3d23e10': ['checkBet()'], + '0xfd68a422': ['returnmoneycreator(uint8,uint128)'], + '0x6673ce2b': ['Results_of_the_last_round()'], + '0x2c329e99': ['Last_block_number_and_bloctime_used()'], + '0xdb641ab4': ['Game_balance_in_Ethers()'], + '0xd6f42038': ['PhoneToAddress()'], + '0x4636a159': ['newPhoneToAddr(address,uint256)'], + '0xe3ffc9a3': ['sendEtherToOwner()'], + '0xb958a5e1': ['getPhoneByAddress(address)'], + '0x1f83f440': ['getPaymentByAddress(address)'], + '0xa02b9aac': ['getPaymentDataByAddress(address)'], + '0xfe97ee88': ['hasPhone(address)'], + '0x11103599': ['Token_Offer(address,address,uint16)'], + '0x7824407f': ['tokenSupply()'], + '0xd0febe4c': ['buyTokens()'], + '0x0e662cf0': ['buyTokens(uint16)'], + '0x8ed67a44': ['setPrice(uint16)'], + '0xdc52696f': ['tokenSupplyChanged()'], + '0xf29d2f28': ['setTokenHolder(address)'], + '0x7b1a4909': ['transferETH(address,uint256)'], + '0x19901f1d': ['TokenSale(uint256,uint256)'], + '0x13d4bc24': ['buyTokenProxy(address)'], + '0xe8038e25': ['TokenSale(uint256,uint256,address)'], + '0x3fc6bc94': ['payDAO()'], + '0x81788e2b': ['addAllowedAddress(address)'], + '0x0b6d8d52': ['createDAO(address,uint256,uint256)'], + '0x656d2f63': ['ManagedAccount(address)'], + '0xb2e85b67': ['getPlayerStatus(address,uint256)'], + '0x1ce624d6': ['Crypted_RPS()'], + '0xb50954b6': ['cancelWaitingForOpponent()'], + '0xa28ecf0b': ['sendCryptedHand(bytes)'], + '0x3f2f46b4': ['revealRock(string)'], + '0xe7740cf9': ['revealPaper(string)'], + '0x953307d8': ['revealScissors(string)'], + '0xe1bc3003': ['reveal(bytes,string)'], + '0xf91a792e': ['decryptHand(string,uint256,uint256,uint256)'], + '0x0cf45ba5': ['updateFirstDuel2(uint256)'], + '0x2d0104a5': ['updateFirstDuel1(uint256)'], + '0x528fd7b0': ['manualPayExpiredDuel()'], + '0x6f52167d': ['payDuel(address,string,address,string)'], + '0xb1418cf4': ['payHouse()'], + '0x717fedf0': ['getFirstActiveDuel1()'], + '0xcb10e0c5': ['getLastDuel1()'], + '0x8dc45377': ['getDuel1(uint256)'], + '0xb782fc9b': ['getFirstActiveDuel2()'], + '0x67bd69a6': ['getLastDuel2()'], + '0x96f7807a': ['getDuel2(uint256)'], + '0xdd10d97e': ['getPlayerWaiting()'], + '0x92093dd6': ['getLastResult()'], + '0x81a60c0d': ['getResults(uint256)'], + '0xb5bfdd73': ['addDSource(string,bytes1,uint256)'], + '0x0f825673': ['deleteCoupon(string)'], + '0xdb37e42f': ['multisetProofType(uint256[],address[])'], + '0xd9597016': ['multisetCustomGasPrice(uint256[],address[])'], + '0x68742da6': ['withdrawFunds(address)'], + '0xca6ad1e4': ['setCustomGasPrice(uint256)'], + '0xa6f9dae1': ['changeOwner(address)'], + '0x64aabe92': ['tryExec(address,bytes,uint256)'], + '0xad8d5f48': ['exec(address,bytes,uint256)'], + '0xa6a20ff6': ['DSEasyMultisig(uint256,uint256,uint256,uint256)'], + '0xc9030ea0': ['addMember(address,bool)'], + '0xc7d6faf1': ['easyPropose(address,uint256)'], + '0x31c2bd0b': ['propose(address,bytes,uint256)'], + '0x1555e337': ['ConferenceCertificate()'], + '0x9844347b': ['createCertificate(bytes,bytes,uint256,bytes)'], + '0x682d3bb0': ['pdfCertificateProof(bytes)'], + '0x73e30e49': ['majorEventFunc(uint256,bytes,bytes)'], + '0x53850db3': ['getParticipantById(uint256)'], + '0xad605729': ['getParticipantCount()'], + '0x28f90e4b': ['Etheramid2()'], + '0xe67cdfb7': ['moveOldUser(uint256)'], + '0xe837ab59': ['getParticipantByAddress(address)'], + '0x9c7e8a03': ['addParticipant(address,address,uint256)'], + '0xd014c01f': ['enter(address)'], + '0xb3ea3924': ['PointlessCoin(int256,uint256,string,uint8,string,address)'], + '0xe724529c': ['freezeAccount(address,bool)'], + '0xf7c9f74a': ['insert_contribution(address,uint256)'], + '0x3f19d043': ['getContributions(address)'], + '0x0a2282ae': ['JackPot()'], + '0xc431f885': ['addToContribution()'], + '0x1f1f5e76': ['addValueToContribution(uint256)'], + '0x6e2cde85': ['drawPot(string,string)'], + '0x8afa08bd': ['setDrawDate(uint256)'], + '0xea3d2827': ['selectWinner(string)'], + '0x744d8b4f': ['recordWin(uint256,uint256)'], + '0x83197ef0': ['destroy()'], + '0x06005754': ['nameRegAddress()'], + '0xf9a7a2ef': ['named(bytes)'], + '0xb028ee13': ['s2b(string)'], + '0x2f570a23': ['test(bytes)'], + '0xcd50d44f': ['CheckRepresentment()'], + '0xa23744f0': ['tryCreateCheckRecord(bytes)'], + '0xfa8dc33a': ['checkRecordExists(bytes)'], + '0x4ac6b2be': ['getCheckRecordCreator(bytes)'], + '0x46e44f63': ['getCheckRecordTS(bytes)'], + '0xa352f1a8': ['calcSHA3(bytes)'], + '0x1eb5ea2e': ['returnFunds()'], + '0x4fa99dd0': ['Matching_Ethers()'], + '0x1a1df394': ['Play(bool)'], + '0xde14bbf7': ['randomGen(uint256,uint256)'], + '0x7f98444f': ['randomEnd()'], + '0x749aa2d9': ['endRound()'], + '0x60f8af90': ['refundRound()'], + '0x51b42b00': ['deactivate()'], + '0xd18611d6': ['reactivate()'], + '0xcbd08c8c': ['config(uint256,uint256,uint256,uint256)'], + '0xd68199dc': ['gameStats()'], + '0xb7297cf3': ['gameSettings()'], + '0xdfc765dc': ['getMatchers_by_index(uint256)'], + '0x3855dcd6': ['getContrarians_by_index(uint256)'], + '0x477801b1': ['getLastRoundResults_by_index(uint256)'], + '0x1c5d9faa': ['setNickname(string)'], + '0xadaccd74': ['getNickname(address)'], + '0xac5e81a9': ['historyPayout(address)'], + '0xd7c23572': ['historyTimesPlayed(address)'], + '0xf4b2dfea': ['Matching_Finneys()'], + '0x7df23b6a': ['ReleaseOracle(address[])'], + '0x46f0975a': ['signers()'], + '0xbf8ecf9c': ['authProposals()'], + '0x64ed31fe': ['authVotes(address)'], + '0x9d888e86': ['currentVersion()'], + '0x26db7648': ['proposedVersion()'], + '0xd0e0813a': ['promote(address)'], + '0x5c3d005d': ['demote(address)'], + '0x01b869f1': ['release(uint32,uint32,uint32,bytes)'], + '0xbc8fbbf8': ['nuke()'], + '0xf460590b': ['updateSigner(address,bool)'], + '0x5bc7e259': ['updateRelease(uint32,uint32,uint32,bytes,bool)'], + '0x60eb2826': ['Badge()'], + '0xee95feaf': ['isSeller(address)'], + '0x64ac2c4a': ['WavesPresale()'], + '0x09957e69': ['newSale(bytes,uint256,uint256)'], + '0x779beca0': ['getNumOfSalesWithSameId(bytes)'], + '0xe2b05077': ['getSaleDate(bytes,uint256)'], + '0x67eae672': ['sendCoinFrom(address,uint256,address)'], + '0xc86a90fe': ['sendCoin(uint256,address)'], + '0xd26c8a8a': ['coinBalance()'], + '0xbbd39ac0': ['coinBalanceOf(address)'], + '0xdaea85c5': ['approve(address)'], + '0x673448dd': ['isApproved(address)'], + '0x1fa03a2b': ['isApprovedFor(address,address)'], + '0x1c14179a': ['GavCoin()'], + '0x99f4b251': ['mine()'], + '0x58150c8b': ['GameRegistry()'], + '0x3c21db0a': ['theGames(uint256)'], + '0xe06174e4': ['settings()'], + '0xe37aa618': ['distributeValue()'], + '0x0d7af726': ['addGame(address,string,string)'], + '0x30945443': ['update(address,string,string)'], + '0xc3c5a547': ['isRegistered(address)'], + '0x617fba04': ['getRecord(address)'], + '0xfa544161': ['getOwner(address)'], + '0x4b70cec4': ['getTime(address)'], + '0x644998ae': ['maintain(int256,uint256,uint256)'], + '0x0aeacb5e': ['getTotalRecords()'], + '0x990c8f79': ['returnValue()'], + '0xea2d4cf8': ['__DeployerFunctions(address,address,uint256)'], + '0x3ac5cb73': ['GeometricPonzi()'], + '0x1b55ba3a': ['Start()'], + '0xe59f611f': ['InputLimit(uint256)'], + '0xcec1365a': ['ShortLimit(uint256)'], + '0xde640e19': ['Investment(uint256)'], + '0xb3dfcdc3': ['Contribution(uint256)'], + '0xa7eeea37': ['NewContributor(uint256)'], + '0x28f03554': ['ProcessDividend()'], + '0xc0b6f0c2': ['NextRoundAndEvents()'], + '0x5afeb106': ['Sqrt()'], + '0x0a4d564c': ['TieUpLooseEnds()'], + '0xdabf7dc8': ['PayoutDividendEarly(uint256,bool)'], + '0x9f9eac67': ['ChangeName(string)'], + '0x68f65f02': ['ChangeShownDenomination(bool,bool,bool,bool)'], + '0x29f27577': ['InvestorList(uint256)'], + '0x8c88752a': ['ContributorList(uint256)'], + '0x979b6f6f': ['RoundInfo()'], + '0x17e875e3': ['Transparancy()'], + '0xc08dd1dc': ['IOU(string,string,uint8)'], + '0xc2a95cc9': ['updateTrustSettings(address,uint256)'], + '0x7682e6ff': ['getTrustSetting(address)'], + '0x4889ca88': ['receiveApproval(address,uint256,address)'], + '0x3177029f': ['approveAndCall(address,uint256)'], + '0xd30fbd0d': ['safeSubtract(uint256,uint256)'], + '0xbe040fb0': ['redeem()'], + '0x4ff13571': ['x2()'], + '0xe97dcb62': ['enter()'], + '0xc8796572': ['collectFees()'], + '0xb6509c12': ['Ethereum_twelve_bagger()'], + '0x421aeda6': ['Set_your_game_number(string)'], + '0x00873367': ['comparisonchr(string)'], + '0x43e332c5': ['Last_block_number_and_blockhash_used()'], + '0xdd36e18b': ['ContractStatus()'], + '0x269975d0': ['GameDetails(uint256)'], + '0x068c966b': ['DrawDetails(uint256)'], + '0x86e4e178': ['CheckTickets(address,uint256,uint256)'], + '0x9bb5239a': ['CheckPrize(address,uint256)'], + '0x83b23b40': ['cEthereumlotteryNet()'], + '0xe56b9dce': ['GetPrize(uint256)'], + '0xd7e11e9d': ['AddTicket(bytes)'], + '0x3fbd40fd': ['ProcessDraw()'], + '0x9d3e069c': ['StartDraw()'], + '0x3211bb90': ['OwnerAddFunds()'], + '0xcc131be1': ['CreateNewDraw(uint256)'], + '0xd1d1c8ae': ['ConvertNumbers(bytes)'], + '0x7154ae61': ['CheckNumbers(uint8[5])'], + '0x05433a26': ['GetNumbersFromHash(bytes)'], + '0x090637a1': ['GetPart(bytes,uint256)'], + '0xe3da41b5': ['sortWinningNumbers(uint8[5])'], + '0x244c23ee': ['Token(uint256,string,uint8,string)'], + '0xe0429b6c': ['ShinySquirrels()'], + '0xc038a38e': ['totals()'], + '0xc8e4acef': ['playerByAddress(address)'], + '0xe46164c5': ['waitingForPayout()'], + '0x030d406b': ['entryPayout(uint256)'], + '0xfd35e71b': ['entryPayoutDue(uint256)'], + '0xb95594e5': ['lineOfPlayers(uint256)'], + '0x93e84cd9': ['play()'], + '0x99c724ef': ['skipInLine(uint256,uint256)'], + '0x67f809e9': ['DynamicPyramid()'], + '0x1da0fb1b': [ + 'updateSettings(uint256,uint256,uint256,uint256,uint256,bool)' + ], + '0x60689557': ['Rock()'], + '0xaf769eff': ['Paper()'], + '0x25ea269e': ['Scissors()'], + '0x00c721ab': ['setHand(uint256)'], + '0xd2b8035a': ['draw(uint256,uint256)'], + '0x2ad95786': ['winner(address)'], + '0x6a0e605f': ['MyToken(uint256,string,uint8,string,address)'], + '0x1b5ee6ae': ['mintToken(int256,address,uint256)'], + '0x2a64fb63': ['getSaleDate(bytes)'], + '0xd8e5ae6a': ['Etheramid()'], + '0xd35ada32': ['addParticipant(address,address)'], + '0x67dd74ca': ['buyTicket(uint256)'], + '0x48d9614d': ['GetFee()'], + '0x2675c123': ['CloseContract()'], + '0x501e8428': ['getPart(bytes,uint256)'], + '0x420a8ac8': ['NanoPyramid()'], + '0xa26dbf26': ['totalParticipants()'], + '0x64d905c0': ['awaitingParticipants()'], + '0x3133f2a7': ['outstandingBalance()'], + '0x6ec3af26': ['addTrustedIssuer(address,bytes)'], + '0x249b4d0b': ['removeTrustedIssuer(address,bytes)'], + '0xd3437fe0': ['assertFact(uint256,bytes)'], + '0x4c4766e8': ['KittenRegistry()'], + '0x3ead67b5': ['changeContractOwner(address)'], + '0x1043dcdf': ['LastIsMe(uint256,uint256)'], + '0xa5f8cdbb': ['buyTicket(address)'], + '0x313b7b19': ['finance()'], + '0xb974b0a3': ['allData()'], + '0x3b355af6': ['baseData()'], + '0x2f29d8c5': ['elapsed()'], + '0x55234ec0': ['remaining()'], + '0xbcc941b6': ['totalWinners()'], + '0x1e2ca0f3': ['updateLeftLottery(address)'], + '0xb2353d69': ['updateRightLottery(address)'], + '0x4a67fa7d': ['setLotteryFee(uint256)'], + '0x5a09f2f4': ['setHouseFee(uint256)'], + '0x5af77fff': ['Contract()'], + '0x315e2f1b': ['setTestString(string)'], + '0xd8c90762': ['addTrustedIssuer(address,string)'], + '0xf24b5779': ['removeTrustedIssuer(address,string)'], + '0xfe05e8b1': ['assertFact(uint256,string)'], + '0x5fb3e119': ['Auction()'], + '0xfe777bcd': ['etherForSale()'], + '0x78e97925': ['startTime()'], + '0x3197cbb6': ['endTime()'], + '0xe6d9bb0f': ['secondsUntilEnd()'], + '0x44691f7e': ['hasStarted()'], + '0xecb70fb7': ['hasEnded()'], + '0x5dd672ec': ['latestBid()'], + '0x63bd1d4a': ['payout()'], + '0xd98b9bb5': ['placeBid(address,uint256)'], + '0x90c3a370': ['AuctionMaster()'], + '0xd5563f31': ['createAuction(uint256)'], + '0xe6690fb1': ['nextAuction(uint256)'], + '0xf2b26d8f': ['nextEtherForSale()'], + '0x7a791524': ['setNextFeePercentage(uint8)'], + '0x5d068051': ['sendFees(address)'], + '0xb40a5627': ['bidCount()'], + '0x2da0d1ea': ['etherSold()'], + '0xdeb6930c': ['PriceTicker()'], + '0xa2e62045': ['update()'], + '0x7bc25372': ['UserCheckBalance(address)'], + '0x53b7b2e9': ['cEthereumlotteryNet(bytes)'], + '0x78e80b39': ['UserGetPrize()'], + '0x2b291eb6': ['UserAddTicket(bytes)'], + '0x3e0663e0': ['AdminDrawProcess()'], + '0xd96de4ce': ['AdminDrawError()'], + '0xe26c8434': ['AdminStartDraw(string,bytes)'], + '0x370b6939': ['AdminSetDrawer(address)'], + '0x0acf473b': ['AdminCloseContract()'], + '0x3fa6497f': ['AdminAddFunds()'], + '0xb6294bde': ['AdminGetFee()'], + '0xc1e5304a': ['CreateNewDraw(uint256,bytes)'], + '0xbf32bf97': ['FailGuyTax()'], + '0x24a852c6': ['unset(bytes)'], + '0x804ba97a': ['tryGet(bytes)'], + '0x2a0d79ef': ['totalSupply(bytes)'], + '0x8606f905': ['balanceOf(address,bytes)'], + '0x5fd9dff6': ['allowance(address,address,bytes)'], + '0xab67aa58': ['transferFrom(address,address,uint256,bytes)'], + '0x5c17f9f4': ['approve(address,uint256,bytes)'], + '0x669dafe8': ['toWei(uint256)'], + '0xe4fc6b6d': ['distribute()'], + '0xb78b52df': ['allocate(address,uint256)'], + '0x6617e11a': ['NiceGuyTax()'], + '0x0a7493b4': [ + 'Etheropt(uint256,string,uint256,uint256,bytes,address,int256[])' + ], + '0x7c7c7695': ['getAccountID(address)'], + '0xce88b145': ['getAccount(uint256)'], + '0xa26759cb': ['addFunds()'], + '0x155dd5ee': ['withdrawFunds(uint256)'], + '0x5c665f89': ['getFunds(address,bool)'], + '0xd5544f94': ['getFundsAndAvailable(address)'], + '0x502414e4': ['marketMaker(string)'], + '0x2043285d': ['getMarketMakers()'], + '0x0e1087c3': ['getMarketMakerFunds()'], + '0x756fb8c9': ['getOptionChain()'], + '0xd4dfadbf': ['getMarket(address)'], + '0xc398f030': ['expire(uint256,uint8,bytes,bytes,bytes)'], + '0xec0b4153': ['getMoneyness(int256,uint256,uint256)'], + '0xc6cb7a96': [ + 'orderMatchTest(uint256,uint256,int256,uint256,uint256,address,address,uint256,int256)' + ], + '0x6663bbec': [ + 'orderMatch(uint256,uint256,int256,uint256,uint256,address,uint8,bytes,bytes,int256)' + ], + '0x17c65aa7': ['getMaxLossAfterTrade(address,uint256,int256,int256)'], + '0x209a5b8a': ['moneySumAtSettlement(address,uint256,int256,uint256)'], + '0x7d619d9b': ['holdCoin(address,address)'], + '0xa66f7ad6': ['signRelease(uint256)'], + '0xbff0fbb8': ['calculateMeat(uint256)'], + '0xb8d3bfe3': [ + 'MeatGrindersAssociation(address,address,uint256,uint256,uint256,address)' + ], + '0x5938748e': ['changeVotingRules(address,address,uint256,uint256,uint256)'], + '0xeb08b304': ['changeMeatProvider(address)'], + '0x677342ce': ['sqrt(uint256)'], + '0x4ae85627': ['grindUnicorns(uint256)'], + '0x9a92b7e7': ['EthVenturesFinal()'], + '0x1097e579': ['Enter()'], + '0x3edd90e7': ['NewOwner(address)'], + '0x6b1781b6': ['Emergency()'], + '0x611daa7e': ['EmergencyBalanceReset(uint256)'], + '0x476e04c7': ['NewMessage(string)'], + '0x4cd11943': ['NewManualInvestor(address,uint256)'], + '0x112c7075': ['ManualDeposit()'], + '0x9f7f760c': ['SimpleDice()'], + '0x8fcc9cfb': ['setMinDeposit(uint256)'], + '0x45596e2e': ['setFeeRate(uint256)'], + '0x4b09ebb2': ['e_exp(uint256)'], + '0x24d4e90a': ['ln(uint256)'], + '0x084d72f4': ['getWinningOutcome(uint256)'], + '0xabebb7f3': ['MarketsContract()'], + '0x74580e2f': ['changeCreator(address)'], + '0x5a58cd4c': ['deleteContract()'], + '0xcdd13701': ['getEventHashes(uint256[256])'], + '0xb2c652f3': ['getMarkets(uint256[128])'], + '0x90e3c278': ['getShares(uint256[128])'], + '0x76abc03b': ['getShareDistribution(uint256)'], + '0xff49b26e': [ + 'createEvent(uint256,uint256,uint8,uint32,address,uint256,uint8)' + ], + '0x7a29332d': ['buyAllOutcomes(uint256,uint256)'], + '0x4757f1d2': ['redeemAllOutcomes(uint256,uint256)'], + '0x154af6b1': ['sendShares(uint256,uint8,uint256,address)'], + '0xd7ed7453': ['redeemWinnings(uint256)'], + '0x1335ff36': [ + 'createEventAndMarketMaker(uint256,uint256,uint8,uint32,address,uint256,uint8,uint16,uint256)' + ], + '0x968908a3': ['createMarketMaker(uint256,uint16,uint256)'], + '0xc7489441': ['closeMarketMaker(uint256)'], + '0x3f887fad': ['buyShares(uint256,uint8,uint256,uint256)'], + '0x590528a9': ['sellShares(uint256,uint8,uint256,uint256)'], + '0x7ef1925b': ['getShareRange(uint256,uint8)'], + '0x550dd006': ['calcCostsBuying(uint256,uint8,uint8,uint256)'], + '0x6111dd02': ['calcCostsSelling(uint256,uint8,uint8,uint256)'], + '0x8112821f': ['EthVentures()'], + '0xa20495d3': ['Managed()'], + '0xb3a2a6c0': ['setOfficialWebsite(string)'], + '0xa49d53a1': ['SmartRevshare()'], + '0x3d750b28': ['found()'], + '0x14ba5c09': ['getDay()'], + '0xcde99727': ['calculateROI()'], + '0x791b51f1': ['Consulting(address,address)'], + '0x51a5f2f2': ['ConsultingHalf(address,address)'], + '0x06900c41': ['ZeroPonzi()'], + '0x61472fd4': ['CSGOBets()'], + '0x940c154b': ['lockBet(uint256)'], + '0xe1152343': ['payout(uint256)'], + '0x85b1423e': ['returnAll()'], + '0xd7a58658': ['changeHouseedge(uint8)'], + '0x41fa4876': ['multiBlockRandomGen(uint256,uint256)'], + '0x340ddda6': ['MeatConversionCalculator(uint256,uint256)'], + '0x6fa8de90': ['changeMeatParameters(uint256,uint256)'], + '0xa80d4e9a': ['EtherAuction(uint256)'], + '0xe1c7392a': ['init()'], + '0x1998aeef': ['bid()'], + '0xfe67a54b': ['endAuction()'], + '0x547eeac1': ['acceptTransfer()'], + '0xed54746e': ['lastAuction()'], + '0xec93cfae': ['FountainOfWealth()'], + '0x2a745971': ['BlockKing()'], + '0x2431f164': ['process_payment()'], + '0x8e035ac1': ['BetOnHashV82()'], + '0x547916ea': ['finishRound()'], + '0xb688a363': ['join()'], + '0x6bf8f85a': ['forceFinish()'], + '0x9eded57a': ['paybackLast()'], + '0x72388610': ['paybackAll()'], + '0x758b5172': ['setPlayersPerRound(uint256)'], + '0x07da68f5': ['stop()'], + '0xa77b2e37': ['Coin()'], + '0xd0679d34': ['send(address,uint256)'], + '0x37ae43a3': ['BetOnHashV81()'], + '0xd850288b': ['etherlist_top()'], + '0x4789aaef': ['EthereumDice()'], + '0xc2e9fab3': ['SubUser()'], + '0x6d853ab6': ['isSubUser(address)'], + '0x018f5472': ['isAUser(address)'], + '0xc5d5997c': ['changeSubUser(address,address)'], + '0x0870607b': ['addSubUser(address)'], + '0x7ccfd45a': ['removeSubUser(address)'], + '0xbaf00f76': ['removeAllSubUsers()'], + '0x1a93fa4b': ['reorganizeSubUsers()'], + '0x8b9e5385': ['MeterSlock(uint256,uint256,address)'], + '0xf5bade66': ['setDeposit(uint256)'], + '0x91b7f5ed': ['setPrice(uint256)'], + '0xb29b5366': ['setRentable(bool)'], + '0xbe9a6555': ['start()'], + '0x6299f8cf': ['stop(uint256)'], + '0xd12c1e28': ['badgesOf(address)'], + '0x70844f7a': ['sendBadge(address,uint256)'], + '0x615664ba': ['Market()'], + '0x177766e6': ['getOptionChain(uint256)'], + '0x5025b9ae': ['expire(uint256,uint256,uint8,bytes,bytes,bytes)'], + '0x0448f79f': [ + 'addOptionChain(uint256,string,uint256,uint256,bytes,address,int256[])' + ], + '0x42bf4431': [ + 'orderMatchTest(uint256,uint256,uint256,int256,uint256,uint256,address,address,int256)' + ], + '0xb3760c80': [ + 'orderMatch(uint256,uint256,uint256,int256,uint256,uint256,address,uint8,bytes,bytes,int256)' + ], + '0xfe4667e9': ['getMaxLossAfterTrade(address,uint256,uint256,int256,int256)'], + '0x69d79ad5': [ + 'moneySumAtSettlement(address,uint256,uint256,int256,uint256,uint256)' + ], + '0xabcf1328': ['InterestBank()'], + '0x6fc9d5e4': ['changeCompareTo(uint256)'], + '0x315fdea3': ['TreasureChest()'], + '0xeebf9808': ['PiggyBank()'], + '0xf9391d24': ['AllPayAuction()'], + '0xecfc7ecc': ['placeBid()'], + '0x6b64c769': ['startAuction()'], + '0xf449619e': ['collectPrize(uint256)'], + '0x003b9d88': ['setLowerFeePercentage(uint8)'], + '0x164e68de': ['withdrawFees(address)'], + '0xdd467064': ['lock(uint256)'], + '0x1aa3a008': ['register()'], + '0x362e2565': ['returnDeposits()'], + '0xcc8b34ab': ['CrowdCoin()'], + '0x9a777d5d': ['buyCoins()'], + '0x84054d3d': ['cashout()'], + '0xa3053236': ['SafeInvestments()'], + '0xc31d0031': ['CrowdFundDAO(string,uint8,string)'], + '0x45755dd6': ['returnFunds(uint256)'], + '0x9b5fde7d': ['payOut(uint256,string)'], + '0x51d38d5f': ['addDeveloper(address,string)'], + '0xd9d73887': ['Diana()'], + '0x8691162a': ['TlcCoin()'], + '0x4b8e1ba8': ['isMinter(int256,address)'], + '0x4594d06a': ['delMinter(int256,address)'], + '0xc478fc37': ['EtherWheel(uint256,uint256,uint8)'], + '0x8f03850b': ['numContributors()'], + '0x8b7bcc86': ['numWinners()'], + '0xe3083fb5': ['removeFromContribution(uint256)'], + '0x88017e05': ['setContribution(uint256)'], + '0x33a99e04': ['selectWinner()'], + '0x739b47ca': ['recordWin(address)'], + '0x6e940a29': ['changeHost(address)'], + '0x4cdc6a73': ['Marriage()'], + '0xce60f78d': ['createMarriage(bytes,bytes,uint256,bytes,bytes)'], + '0xaf408d89': ['setStatus(bytes)'], + '0x26826bf8': ['setImage(bytes)'], + '0xe771066f': ['marriageProof(bytes)'], + '0x6f3a7561': ['SimpleAuction(address)'], + '0x2a24f46c': ['auctionEnd()'], + '0x824dbc9a': ['changeMembership(address,uint256,bool,string)'], + '0x522103fa': ['changeUnicorn(uint256,address)'], + '0x83876bc9': ['newProposalInWei(address,uint256,string,bytes)'], + '0xb9f256cd': ['newProposalInEther(address,uint256,string,bytes)'], + '0x0358d965': ['addPayout(uint256)'], + '0x686f2c90': ['collectAllFees()'], + '0xb4022950': ['collectFeesInEther(uint256)'], + '0x4229616d': ['collectPercentOfFees(uint256)'], + '0xced92670': ['changeMultiplier(uint256)'], + '0xfae14192': ['changeFeePercentage(uint256)'], + '0x6fbaaa1e': ['currentMultiplier()'], + '0x8a5fb3ca': ['currentFeePercentage()'], + '0x09dfdc71': ['currentPyramidBalanceApproximately()'], + '0x57d4021b': ['nextPayoutWhenPyramidBalanceTotalsApproximately()'], + '0x253459e3': ['feesSeperateFromBalanceApproximately()'], + '0xd11f13df': ['numberOfParticipantsWaitingForPayout()'], + '0x9dbc4f9b': ['participantDetails(uint256)'], + '0xea851885': ['buyStake(bool)'], + '0x7c3064f1': ['refundStake()'], + '0x20909fa0': ['communityCurrency()'], + '0x7817a60f': ['acceptMember(address,string)'], + '0xd9e947f3': ['kickOutMember(address)'], + '0xa5ea11da': ['getParameters()'], + '0xa5ebf389': ['getMoneyTotals()'], + '0xac4b2bae': ['newParameters(int256,uint256,int256,uint256)'], + '0x8da4d776': ['newCommune(address)'], + '0x9718b524': ['newTreasury(address)'], + '0x127714c7': ['getBudget()'], + '0x69c4113d': ['setNewBudget(uint256,uint256,uint256,uint256)'], + '0x69433e12': ['setExchange(uint256)'], + '0x70ab8ba8': ['creditUpdate()'], + '0xddb1bdc8': ['credit(address,uint256,uint256)'], + '0x1bad1d2e': ['monitorWallet(address)'], + '0x1b9f9647': ['accessMyWallet(address)'], + '0x85f8c16d': ['claimHours(int256)'], + '0x6a357465': ['payHours(address,uint256)'], + '0xea5ea470': ['payFunding(uint256)'], + '0x4f20f35a': ['payExpenses(address,uint256)'], + '0xc81caae7': ['acceptMember(address,string,string)'], + '0x80aed05f': ['LooneyDice()'], + '0xef7507c8': ['testWinner(uint256)'], + '0xcd5e3c5d': ['roll()'], + '0x699b328a': ['randomize()'], + '0x5601eaea': ['execute(uint256,uint256)'], + '0x4aa16737': ['enter(uint8)'], + '0x33f707d1': ['ownerWithdraw(uint256)'], + '0x37ab8f20': ['notifyPlayer(uint256,uint256,uint256,uint256)'], + '0xc2fb8f36': ['TinyHuman(address,address,address)'], + '0xad5c613d': ['purchase(bytes)'], + '0xd50495f4': ['addTransaction(bytes)'], + '0xb7f2f33c': ['transferRightIfApproved(address,bytes)'], + '0xed3058e0': ['transferRight(address,bytes)'], + '0xeba36dbd': ['setAddr(uint256,address)'], + '0x0790e880': ['setBlockappsAddr(address)'], + '0x8eec99c8': ['setNewAdmin(address)'], + '0x3d6a3664': ['setNewOracle(address)'], + '0x7ba38916': ['changeAdminFromBoard(address)'], + '0x279e0912': ['getDownloadPrice()'], + '0xb83069c5': ['getStemPrice()'], + '0xa33d4968': ['Tripler()'], + '0xe977992d': ['Doubler()'], + '0xa88c5ef7': ['NextPayout()'], + '0x8cf4dbfb': ['collectBalance()'], + '0x3169ff3e': ['LooneyLottery()'], + '0x4311de8f': ['ownerWithdraw()'], + '0x5d495aea': ['pickWinner()'], + '0xb94e962a': ['allocateTickets(uint256)'], + '0x1b83b823': ['notifyPlayer(uint256)'], + '0xc0a963c9': ['notifyWinner(address,uint256)'], + '0x5d3278f0': ['LooneyFifty()'], + '0x7bc49a95': ['play(uint256,uint256)'], + '0x2262cd94': ['wroom()'], + '0xd1738b72': ['wroomWroom()'], + '0x6d7da0b1': ['MyContract()'], + '0x7bb6a4c6': ['uno(uint256)'], + '0xa5468081': ['Pyramid(address)'], + '0x54ba7daa': ['enter(bytes,bytes)'], + '0xc80c28a2': ['getNumberOfParticipants()'], + '0xa480ca79': ['collectFees(address)'], + '0x483ba09e': ['setBitcoinBridge(address)'], + '0x02dc2e1d': ['queuePayment(bytes)'], + '0x27d6c032': ['unregister(bytes)'], + '0x6b4dd158': ['getPrice(bytes)'], + '0x7a6e9df7': ['getTimestamp(bytes)'], + '0x08b7fa31': ['PriceFeed()'], + '0xd249a52e': ['update(bytes,uint256[],uint256[])'], + '0x43d24a5e': ['addUpdater(address)'], + '0x04b07a5e': ['removeUpdater(address)'], + '0x76999896': ['KingOfTheEtherThrone()'], + '0xc8fdc891': ['numberOfMonarchs()'], + '0xb66a323c': ['claimThrone(string)'], + '0x0eb3f5a0': ['sweepCommission(uint256)'], + '0x55cc4e57': ['setIssuer(address)'], + '0x566735d8': ['PreVNK(uint256,string,string,uint8)'], + '0xb5d03751': ['YoutubeViews()'], + '0xaacf5328': ['setVideoID(string,uint256)'], + '0x788e26e7': ['sponsorDeposit()'], + '0x2a228fc2': ['processWithdrawals()'], + '0x01518d76': ['sendQuery(uint256)'], + '0x23145ca0': ['forceCheck()'], + '0x918f1bb5': ['ProjectKudos()'], + '0xd56b2889': ['finish()'], + '0x72929b56': ['getKudosPerProject(address)'], + '0x505ff574': ['register(address,uint256,bool)'], + '0xec3af4a9': ['getProjectKudos(address)'], + '0x94f60a63': ['getKudosLeft(address)'], + '0xe116b17e': ['getKudosLeftForProject(address,address)'], + '0xf4a81d08': ['getKudosGiven(address)'], + '0xda82a035': ['sweepCommission()'], + '0x2004dff6': ['Basics()'], + '0xc0aa18e7': ['History()'], + '0x84ebde52': ['Under_the_Hood()'], + '0xa9f6def0': ['HonestDice()'], + '0xaa9669c1': ['roll(uint256,bytes)'], + '0xa48566ba': ['serverSeed(address,bytes)'], + '0x59dac714': ['hashTo256(bytes)'], + '0xaa1e84de': ['hash(bytes)'], + '0xa094a031': ['isReady()'], + '0x2fac1d36': ['isReadyFor(address)'], + '0xef4592fb': ['getResult(bytes)'], + '0xf93589ce': ['didWin(bytes)'], + '0x06b5f02d': ['calcWinnings(uint256,uint256)'], + '0x2d9a37d3': ['getMaxPayout()'], + '0xc63ff8dd': ['claim(bytes)'], + '0xc7cf28fe': ['canClaimTimeout()'], + '0x0e1da6c3': ['claimTimeout()'], + '0x839930ba': ['getMinimumBet()'], + '0x0d1fce42': ['getBankroll()'], + '0x021991e7': ['getBetsLocked()'], + '0x55b775ea': ['setFeed(address)'], + '0x46b305d6': ['lockBetsForWithdraw()'], + '0xa1b9af31': ['unlockBets()'], + '0xc47bc007': ['add_funds()'], + '0xcce81927': ['EtherDice(address,address)'], + '0x89ef40e7': ['numberOfHealthyGenerations()'], + '0x918359c6': ['needsBirth()'], + '0x97950740': ['roomForBirth()'], + '0x32cea83e': ['birth(bytes)'], + '0xb3c1a588': ['parseMsgData(bytes)'], + '0x827ef325': ['_parseMsgData(bytes)'], + '0x83e78b31': ['bet(uint8,bool,uint8)'], + '0x21520c5f': ['calculatePayout(uint8,bool,uint256)'], + '0x2df8e00d': ['becomeMortal(uint256)'], + '0xe94a4db1': ['isSuitableGen(uint256,uint256)'], + '0x640f244b': ['findSuitableGen()'], + '0x62770252': ['needsFuneral(uint256)'], + '0xfed4614b': ['funeral(bytes,int256)'], + '0xf004073a': ['performAction(uint256)'], + '0x0fa9ced4': ['emergencyFuneral()'], + '0x99bb875c': ['funeralAndBirth(bytes,int256,bytes)'], + '0x44dd4b3b': ['lookupGeneration(uint256)'], + '0x784813e0': ['lookupBet(uint256,uint256)'], + '0xd5a4a3c6': ['findRecentBet(address)'], + '0xfe72e717': ['toDie(bytes)'], + '0x69bdfd3a': ['toContractDie(bytes,bytes,uint256)'], + '0x61886014': ['combineDice(uint8,uint8)'], + '0xe0457884': ['betResolution(uint8,uint8,uint8,bool)'], + '0x67acd805': ['lowerMinWager(uint256)'], + '0x03bda14e': ['raiseMaxNumBets(uint256)'], + '0xe87508be': ['investorDeposit()'], + '0xe6febc9b': ['investorWithdraw(uint256)'], + '0xd7206124': ['setInvestorLock(bool)'], + '0x0c1fad51': ['setSeedSourceA(address)'], + '0x6615dd83': ['setSeedSourceB(address)'], + '0xcd591822': ['CanaryV7Fast()'], + '0x21a49ec2': ['LCoin()'], + '0x02ba8742': ['sendCoins(address,uint256)'], + '0x3288eb0b': ['ChineseCookies()'], + '0x47b47102': ['bakeCookie(string)'], + '0xb78bd4a5': ['breakCookie(string)'], + '0xfce59d0c': ['MangoRepo()'], + '0xceebe28d': ['repoInterfaceVersion()'], + '0x80d9eaa6': ['refCount()'], + '0x8c79a24d': ['refName(uint256)'], + '0x9d170c5d': ['getRef(string)'], + '0x7d89ae63': ['__findRef(string)'], + '0x8bb0faee': ['setRef(string,string)'], + '0x5ae5df8f': ['deleteRef(string)'], + '0xadd82871': ['strEqual(string,string)'], + '0x098ab6a1': ['snapshotCount()'], + '0x76f10ad0': ['getSnapshot(uint256)'], + '0xfee6d28c': ['addSnapshot(string)'], + '0x8ac6a869': ['isObsolete()'], + '0x5cac8b27': ['amazing()'], + '0x04106c8b': ['startGeneration()'], + '0x434cb64c': ['startNextGeneration()'], + '0x11149ada': ['getProof(uint256)'], + '0x34c1b4ba': ['sha(bytes)'], + '0xf34ed4e6': ['RanDAOPlus(address)'], + '0x696bda86': ['submitProposal(uint256,bytes)'], + '0x141c4e60': ['challenge(uint256,address)'], + '0xd2756e11': ['finalizeNumber(uint256)'], + '0x28472c6c': ['claimComputation(bytes,bytes)'], + '0x287418e7': ['query(uint256,uint16)'], + '0xc3169ef2': ['respond(uint256,uint256[4])'], + '0xa068e8d3': ['convict(uint256,uint256,uint256,uint256)'], + '0x3f5e268f': ['convictInitial(uint256,uint256)'], + '0x89495172': ['convictFinal(uint256,uint256)'], + '0x87393bc6': ['verifyFirstHalf(uint256[4],uint256[4])'], + '0x6bc3e0f0': ['verifySecondHalf(uint256[4],uint256[4],uint256[4])'], + '0x00b5b223': ['computeResponse(uint256,uint16)'], + '0x990f3f53': ['computeResponseSecondHalf(uint256,uint16)'], + '0xe6e8c692': ['computeResponseFirstHalf(uint256,uint16)'], + '0x3b996f40': ['quarter(uint32,uint32,uint32,uint32)'], + '0x669e48aa': ['get(uint256,uint256)'], + '0x541aea0f': ['put(uint256,uint256)'], + '0xf2b445ad': ['rowround(uint256,uint256)'], + '0x6189be15': ['columnround(uint256,uint256)'], + '0x75ee85bd': ['salsa20_8(uint256,uint256)'], + '0x692ad3a9': ['round(uint256,uint256,uint256,uint256)'], + '0x19c32e0b': ['hmacsha256(bytes,bytes)'], + '0x15c91115': ['pbkdf2(bytes,bytes,uint256)'], + '0x7c7a52bf': ['newChallenge(uint256,address)'], + '0xbbdb31cb': ['challenge(uint256,address,bool)'], + '0x9af8c4ba': ['respond(uint256,address,bytes)'], + '0x18968a03': ['finalize(uint256,address,address)'], + '0xd500dd6a': ['challengeTimeout(uint256,bool,address)'], + '0x0ee07836': ['adjustDifficulty(uint256)'], + '0x60b1e173': ['getProof(uint256,address,address)'], + '0x98d5fdca': ['getPrice()'], + '0xd4871517': ['BTCLotto(address,uint256)'], + '0xc5b1d9aa': ['newRound()'], + '0xda333ca6': ['payOut(uint256)'], + '0x8f1327c0': ['getRound(uint256)'], + '0x0699d07d': ['updateMaxVal()'], + '0x1f794436': ['getBlockHeader(int256)'], + '0x02394872': ['getLastBlockHeight()'], + '0x09dd0e81': ['getBlockchainHead()'], + '0x0aece23c': ['getFeeAmount(int256)'], + '0x44d03ac6': ['BlockhashFetch(address)'], + '0x32254992': ['getPrevHash(int256)'], + '0x2cce81aa': ['getBlockHash(int256)'], + '0x66772438': ['computeResponse(uint16)'], + '0x2776a859': ['computeResponseSecondHalf(uint16)'], + '0xfe13a823': ['computeResponseFirstHalf(uint16)'], + '0x954ab4b2': ['say()'], + '0xd6d22fa4': ['MetaCoin()'], + '0x7bd703e8': ['getBalanceInEth(address)'], + '0x87def081': ['getFeeRecipient(int256)'], + '0xa0f61310': ['FakeRelay(bytes)'], + '0x96e4ee3d': ['convert(uint256,uint256)'], + '0xfa2acd87': ['G(uint64[16],uint256,uint256,uint256,uint256,uint64,uint64)'], + '0x33232609': ['blake2b(uint64[],uint64[],uint64)'], + '0x217311ac': ['getWords(uint64)'], + '0xfb72d24e': ['shift_right(uint64,uint256)'], + '0xbf187478': ['shift_left(uint64,uint256)'], + '0x0e47c76f': ['rotate(uint64,uint256)'], + '0x10142785': ['assign(bytes,uint256,bytes1)'], + '0xd985f122': ['RelayToolsTest()'], + '0xa54a2b8b': ['testBlockHashFetch()'], + '0x72c87075': ['testBlockHeaderFetch()'], + '0xedede601': ['testBalance()'], + '0x9a79f4a8': ['testFailHeaderInsufficientFee()'], + '0xfb95adeb': ['testFailBlockhashInsuffiecientFee()'], + '0xad82dcac': ['testBlockhashCorrectFee()'], + '0x70c9edb7': ['BTCRelayTools(address)'], + '0x4016535a': ['parseBlock(bytes,uint256)'], + '0xee82ac5e': ['getBlockHash(uint256)'], + '0xae6215d8': ['getBlockHeight(bytes)'], + '0x19c47214': ['getBlockVersion(bytes)'], + '0x726ab4ef': ['getParentHash(bytes)'], + '0xd9c67404': ['getMerkleRoot(bytes)'], + '0xf74100e3': ['getBits(bytes)'], + '0x51d6e547': ['getNonce(bytes)'], + '0x66aa6f26': ['payFee(bytes)'], + '0xde39acea': ['get32(bytes,uint256)'], + '0xdf5cc291': ['get4(bytes,uint256)'], + '0x745a8be2': ['flip32(bytes)'], + '0x26c7edaa': ['flip4(bytes)'], + '0x0b74edc6': ['testFinalHash()'], + '0x2f597e71': ['testLongInput()'], + '0xa7e25683': ['testShortOutput()'], + '0x6af2da2f': ['testKeyedHash()'], + '0xd299dac0': ['blake2b(bytes,bytes,uint64)'], + '0xd063f55f': ['toLittleEndian(uint64)'], + '0xd18dfdc9': ['parrot(uint256)'], + '0x5168afa4': ['getPackageHash(bytes,uint8,uint8,uint8)'], + '0x027a5e3f': ['getLastVersion(bytes)'], + '0xa587da29': ['setPackage(bytes,uint8,uint8,uint8,bytes)'], + '0x3cc8daf7': ['setNameOwner(bytes,address)'], + '0x44dfdce0': ['getNameOwner(bytes)'], + '0x4112b7f1': ['tryGetNameOwner(bytes)'], + '0x03da8902': ['transfearDBOwner(address)'], + '0x992c870d': ['transferName(bytes,address)'], + '0x8efc777f': ['isBeta(bytes)'], + '0xd1d3bb92': ['testSetPkg()'], + '0x8bab8791': ['testPkgUpdate()'], + '0xb5784f6f': ['testMultiplePackages()'], + '0x96013c9c': ['testLatestPkgGetter()'], + '0x74d89c47': ['testUpdateNameDb()'], + '0x408938d0': ['testUpdatePackageDb()'], + '0x930a80b4': ['testAuthorizedSetPackage()'], + '0x70be4ffa': ['testErrorUnauthorizedSetPackage()'], + '0xb9a904f9': ['testUnauthorizedSetBetaPackage()'], + '0x8a341c83': ['testErrorRootAuthorityChangeUnownedPackage()'], + '0x88a49164': ['testErrorUnauthorizedTransfer()'], + '0x337b5988': ['testSimpleNameRegister()'], + '0xeca5c793': ['testErrorUnauthorizedNameRegister()'], + '0x3e4565d2': ['testErrorUnauthorizedNameRegister2()'], + '0x36344022': ['testAuthorizedTransfer()'], + '0xb189ad2a': ['testErrorUnauthorizedAfterTransfer()'], + '0x0f5381f1': ['testUserCanIncreaseVersionNumber()'], + '0x5babb758': ['testSetUp()'], + '0xaf6fe8e2': ['testGetToken()'], + '0xec2ec781': ['testFailGetUnsetToken()'], + '0xad447a19': ['getBalanceDB()'], + '0xec727000': ['getApprovalDB()'], + '0x9cbf9e36': ['createToken()'], + '0xe6c3b4ab': ['testBalanceAuth()'], + '0x07b6f631': ['testTestHarnessAuth()'], + '0xc89f8f08': ['testGetController()'], + '0x0fe234ed': ['testSetController()'], + '0x4fab2ca4': ['testGetFrontend()'], + '0x9131d803': ['testSetFrontend()'], + '0x7353f62b': ['testGetApprovalDb()'], + '0x4df53a0f': ['testSetApprovalDb()'], + '0xea7a7184': ['testGetBalanceDb()'], + '0xd0bff051': ['testSetBalanceDb()'], + '0x2977b1b1': ['testAllowanceStartsAtZero()'], + '0xf3e3c629': ['testBalanceOfStartsAtZero()'], + '0xfb09b1ac': ['testBalanceOfReflectsTransfer()'], + '0xeb7492d1': ['testTotalSupply()'], + '0x730720b8': ['testControllerValidTransfers()'], + '0x0d8b5fa2': ['testControllerValidTransferFrom()'], + '0x1f2e886c': ['testControllerTransferTriggersEvent()'], + '0x2f5d3916': ['testControllerApproveTriggersEvent()'], + '0xa32f0f41': ['testFailControllerUnapprovedTransferFrom()'], + '0x6f4812e2': ['testFailControllerInsufficientFundsTransfer()'], + '0x296ed88f': ['testFailControllerInsufficientFundsTransferFrom()'], + '0xe50dce71': ['testControllerApproveSetsAllowance()'], + '0xf712d7ff': ['testFailControllerTransferFromWithoutApproval()'], + '0x821e9169': ['testFailControllerChargeMoreThanApproved()'], + '0x7f924c4e': ['testDeposit()'], + '0xd509b16c': ['testWithdraw()'], + '0x23de6651': ['emitTransfer(address,address,uint256)'], + '0x5687f2b8': ['emitApproval(address,address,uint256)'], + '0x2b4a3b31': ['doTransferFrom(address,address,uint256)'], + '0x0f24f5c8': ['doTransfer(address,uint256)'], + '0xa8484938': ['doApprove(address,uint256)'], + '0xfa566ddd': ['doAllowance(address,address)'], + '0xbc2a4dd6': ['doBalanceOf(address)'], + '0x0994a0a0': ['DSTokenTest()'], + '0x6632a507': ['testSetupPrecondition()'], + '0x10922cc1': ['testTransferCost()'], + '0xe13dc28b': ['testValidTransfers()'], + '0x61e539da': ['testFailWrongAccountTransfers()'], + '0xe7faecec': ['testFailInsufficientFundsTransfers()'], + '0x833b4596': ['testApproveSetsAllowance()'], + '0xb9a0a708': ['testChargesAmountApproved()'], + '0x5fe22c8b': ['testFailTransferWithoutApproval()'], + '0xbfc3cd2f': ['testFailChargeMoreThanApproved()'], + '0xc1829a14': ['testFailTooFewConfirms()'], + '0x77e4fb04': ['testFailNotEnoughValue()'], + '0xdf3a6b10': ['testMemberAddedEvent()'], + '0x0caf9d39': ['testFailTooManyMembers()'], + '0xa04a0908': ['execute(address,bytes,uint256)'], + '0x039a21b8': ['tryExecute(address,bytes,uint256)'], + '0x28a45038': ['testTryProxyCall()'], + '0x60a60fd8': ['testProxyCallWithValue()'], + '0xdd5244b4': ['testTryProxyCallWithValue()'], + '0x3358d2d3': ['buildDSTokenFrontend()'], + '0xa7c5052e': ['buildDSTokenRegistry()'], + '0xb8d94b95': ['buildDSNullMap()'], + '0x510f44cb': ['TestFactoryUser()'], + '0xd3ea3322': ['testBuildTokenSystemCost()'], + '0x2c60a055': ['MapTest()'], + '0x0e757a2e': ['testSetAndGet()'], + '0x2f0b15f6': ['testGetUnset()'], + '0x1dda5c7d': ['testFailSubBalanceBelowZero()'], + '0x9bac8602': ['testFailAddBalanceAboveOverflow()'], + '0x953a7fab': ['testMoveBalance()'], + '0xd930a90b': ['testFailMoveBalanceDueToInsufficientFunds()'], + '0x0cee22e9': ['testSetBalanceSetsSupply()'], + '0xcd9380d5': ['testSetBalanceSetsSupplyCumulatively()'], + '0x6f4dd69c': ['testSetBalanceUpdatesSupply()'], + '0x0c9fcec9': ['setApproval(address,address,uint256)'], + '0x89fcd099': ['getApproval(address,address)'], + '0xa005b87b': ['NullMapTest()'], + '0x4bd70ea3': ['testFailGetUnset()'], + '0x7d287697': ['testTryGetUnset()'], + '0x4464aec7': ['testTryGet()'], + '0x62a0b56b': ['testUnset()'], + '0x013d64bd': ['setCanCall(address,address,string,bool)'], + '0x2a714078': ['triggerAuth()'], + '0x6cb3d30a': ['triggerTryAuth()'], + '0x31db4b95': ['doTriggerAuth()'], + '0xd42bf301': ['doTriggerTryAuth()'], + '0xfe6f0d82': ['testConstructorEvent()'], + '0x9e920587': ['testOwnedAuth()'], + '0x7ac91cc2': ['testFailOwnedAuth()'], + '0xd3aa831f': ['testOwnedTryAuth()'], + '0xcae523c1': ['testOwnedTryAuthUnauthorized()'], + '0xaa7dcd84': ['testUpdateAuthorityEvent()'], + '0x9205fbc2': ['testAuthorityAuth()'], + '0x8fd28bcf': ['testFailAuthorityAuth()'], + '0x31ab4066': ['testAuthorityTryAuth()'], + '0xfd339d18': ['testAuthorityTryAuthUnauthorized()'], + '0x5858ef10': ['testErrorNonOwnerCantBreach()'], + '0x138cc941': ['testErrorTransferToRejectAuthority()'], + '0xda6b31b9': ['testErrorTransferToNullAuthority()'], + '0x4e209678': ['testFailBreach()'], + '0x399fdb86': ['testFailNormalWhitelistReset()'], + '0x5dcdddd1': ['testSafeToAddFix()'], + '0xc1c0e9c4': ['exec()'], + '0x3f74fecb': ['DSTrueFallbackTest()'], + '0x8a46bf6d': ['testFallback()'], + '0x92c8eb96': ['DSFalseFallbackTest()'], + '0x01bb85a4': ['__startBlock(string)'], + '0xc7102df7': ['__stopBlock()'], + '0x661e3605': ['ConstructorContract(uint256)'], + '0x1d57bcf7': ['ProofLibInterface()'], + '0x1f4e996b': ['challenge(bool)'], + '0xa991cb0e': ['respond(uint256)'], + '0x5c5d625e': ['getProof()'], + '0x92d0d153': ['t()'], + '0x11f72496': ['testT()'], + '0xd992bd5b': ['testResultNotZero()'], + '0xea2ea847': ['testChallengeFinalize()'], + '0x4b729aff': ['buyNumber(uint256)'], + '0x9dafbc13': ['initBlock(uint256)'], + '0xe2bbb158': ['deposit(uint256,uint256)'], + '0x201dcd7a': ['newChallenge(uint256,uint256)'], + '0x43114842': ['acceptChallenge(uint256,uint256,uint256)'], + '0x3c0870ae': ['challenge(uint256,uint256,uint256,bool)'], + '0xab09ee80': ['respond(uint256,uint256,uint256,uint256)'], + '0xb6013cef': ['finalize(uint256,uint256)'], + '0xf869b11a': ['declareVictor(uint256,uint256)'], + '0x9f489e4e': ['getDeposit(uint256,address)'], + '0xa0befa94': ['getStake(uint256,uint256)'], + '0x33637d5a': ['getPendingBlock(uint256)'], + '0x28cc413a': ['getProof(uint256,uint256,uint256)'], + '0xc37ff3d9': ['sha(uint256,uint256)'], + '0xf77a0923': ['BitcoinProcessor(address)'], + '0x1c0b6367': ['processTransaction(bytes,uint256)'], + '0x2b861629': ['storeBlockHeader(bytes)'], + '0xcef887b0': ['storeBlockWithFee(bytes,int256)'], + '0x6ebf10fe': ['storeHeader(bytes,address)'], + '0x540cafe0': ['storeHeaderWithFee(bytes,int256,address)'], + '0x7cc48875': ['Slots()'], + '0x3b84edbd': ['setRNG(address)'], + '0xd65ab5f2': ['startGame()'], + '0xeec3cb41': ['placeBet(bool[],uint256,uint256)'], + '0xac6bc853': ['startSpin()'], + '0x934354e7': ['finishSpin()'], + '0x93c94acb': ['calculateRewards(uint256[3][3])'], + '0x00100a18': ['NewPoll(string,string,uint256,uint256)'], + '0x1277e24f': ['payOneTimeFee()'], + '0xfc36e15b': ['vote(string)'], + '0x9a36f932': ['feeDivisor()'], + '0x8d99b2eb': ['endPoll()'], + '0x224993c2': ['setTimeBlock(uint256)'], + '0xfcfff16f': ['open()'], + '0x776d62f6': ['costs()'], + '0x82996d9f': ['rent()'], + '0x5ca8bc52': ['returnIt()'], + '0x8ecc0950': ['returnToOwner()'], + '0xfb5d5729': ['getPongvalTransactional()'], + '0x3af94817': ['getPongvalRemote()'], + '0x40193d17': ['getPongvalConstant()'], + '0xf4d94699': ['EndowmentRetriever()'], + '0xfab43cb1': ['getPongAddress()'], + '0xf00aac7f': ['ArrayRR()'], + '0x6c6f1d93': ['getContractCreationValue()'], + '0xa311dd70': ['setArray(uint8[10])'], + '0xf239e528': ['sendOneEtherHome()'], + '0xb8c86aa6': ['getArraySettingResult()'], + '0xd504ea1d': ['getArray()'], + '0x80db79d9': ['StructAndFor()'], + '0x181be00d': ['getValue(uint8)'], + '0x4166c1fd': ['getElevation(uint8,uint8)'], + '0xa3747fef': ['register(bytes,bytes)'], + '0x5460ef10': ['sendWithExtraGas(address,uint256,uint256)'], + '0x5dac1601': ['SimpleStablecoin()'], + '0xbe7cddf8': ['TwoD()'], + '0x1ebe5c0f': ['sendWithAllOurGasExcept(address,uint256,uint256)'], + '0x557ed1ba': ['getTime()'], + '0x0e13b9af': ['getValue(uint8,uint8)'], + '0x3ab1e703': ['roundMoneyDown3SF(uint256)'], + '0x880cdc31': ['updateOwner(address)'], + '0xd4088e33': ['setPrice(uint256,uint256,uint64)'], + '0x992ae976': ['isSafePunctuation(bytes1)'], + '0x6f8b44b0': ['setMaxSupply(uint256)'], + '0xdb2a0cb7': ['HumanStandardTokenFactory()'], + '0xbe592488': ['validateName(bytes)'], + '0x64edfbf0': ['purchase()'], + '0xa2f3ede2': ['computeNameHash(bytes)'], + '0xfc94dd18': ['verifyHumanStandardToken(address)'], + '0xfe757fb5': ['lastClaimPrice()'], + '0xd35b9d83': ['codeAt(address)'], + '0x64325ddb': ['currentClaimPrice()'], + '0x08216c0f': ['createHumanStandardToken(uint256,string,uint8,string)'], + '0x4f8e624e': ['Greeter(string)'], + '0x5fbddcf3': ['isLivingMonarch()'], + '0x42cbb15c': ['getBlockNumber()'], + '0x2ea459b8': ['claimThrone(bytes)'], + '0xa15afb48': ['Replicator()'], + '0xd6d902c4': ['claimThroneFor(bytes,address)'], + '0xa4136862': ['setGreeting(string)'], + '0x70961774': ['getBlockCreatedOn()'], + '0x59a547b0': ['recordCommission(uint256)'], + '0x715ef4ff': ['resendFailedPayment(uint256)'], + '0x19a278b9': ['getBAddress()'], + '0xe6e91cfc': ['voidFailedPayment(uint256)'], + '0xcb553ac9': ['sweepWizardCommission(uint256)'], + '0xd96aee49': ['MultipleConstructorTest()'], + '0x2d116186': ['deityBalance()'], + '0xa819819b': ['sweepDeityCommission(uint256)'], + '0x705eeb90': ['MultipleConstructorTest(bool)'], + '0xedb27f4e': ['switchWizard(address)'], + '0x1e223143': ['getFirst()'], + '0xa70a9ad7': ['switchDeity(address)'], + '0xdce4a447': ['at(address)'], + '0x1b03316f': ['getSecond()'], + '0xc1c723f4': ['validateProposedMonarchName(bytes)'], + '0x6d1f00a6': ['ThroneMaker(uint256)'], + '0xf2080ba6': ['Pong(int8)'], + '0x273bc3c9': ['numberOfThrones()'], + '0x1a092541': ['getDescription()'], + '0x23a1c271': ['setPongval(int8)'], + '0x931df75f': ['validateProposedThroneName(bytes)'], + '0x694e0d5b': ['StringPasser(uint8[])'], + '0xa396541e': ['getPongvalTxRetrievalAttempted()'], + '0x01df7f30': [ + 'validateProposedThroneConfig(uint256,uint256,uint256,uint256)' + ], + '0x16870257': ['getTileDescription(uint8,uint8)'], + '0x5581004d': ['createThrone(bytes,uint256,uint256,uint256,uint256)'], + '0x044f9ac8': ['findThroneCalled(bytes)'], + '0xd8589be3': ['CoinFlipper()'], + '0xb3a0b1ef': ['basicInfoGetter()'], + '0xf4e36afd': ['findThroneByNameHash(uint256)'], + '0x5acce36b': ['getEndowmentBalance()'], + '0x4ca8b0d0': ['registerExistingThrone(bytes,address,uint256,uint256)'], + '0xf8f46b5f': ['getCurrentMinerAddress()'], + '0xf9e05ed9': ['sha(uint128)'], + '0x2f4ee5d4': ['registerThrone(bytes,uint256,address,uint256,uint256)'], + '0x25d8dcf2': ['betAndFlip()'], + '0xa1188e56': ['getCurrentDifficulty()'], + '0x58ea80e5': ['setThroneCreationPrice(uint256)'], + '0x34dbe44d': ['getLastBlockNumberUsed()'], + '0x92b7d5b9': ['getCurrentGaslimit()'], + '0x94c3fa2e': ['getLastBlockHashUsed()'], + '0xee6d2641': ['sendWithExtraGasExt(address,uint256,uint256)'], + '0x6fd902e1': ['getCurrentBlockNumber()'], + '0xcee6f93c': ['getResultOfLastFlip()'], + '0x5294157f': ['sendWithAllOurGasExceptExt(address,uint256,uint256)'], + '0x796b89b9': ['getBlockTimestamp()'], + '0x0efafd01': ['getPlayerGainLossOnLastFlip()'], + '0x4b5dc8cb': ['roundMoneyDown3SFExt(uint256)'], + '0xc8e7ca2e': ['getMsgData()'], + '0x4d536f9f': ['validateNameExt(bytes)'], + '0x7a6ce2e1': ['getMsgSender()'], + '0x635cfda2': ['Incrementer()'], + '0x7fd8ee68': ['computeNameHashExt(bytes)'], + '0xa17042cc': ['getMsgValue()'], + '0xfc2c3e08': ['getIteration()'], + '0x9d5c6061': ['getMsgGas()'], + '0x77e5bf84': ['getTxGasprice()'], + '0xb8077e28': ['getTxOrigin()'], + '0xe31bfa00': ['next_id()'], + '0x32a2c5d0': ['getContractAddress()'], + '0x26066ad5': ['offer(uint256,bytes,uint256,bytes)'], + '0xc3da42b8': ['c()'], + '0x6f9fb98a': ['getContractBalance()'], + '0xb742398b': ['trade(address,uint256,bytes,address,uint256,bytes)'], + '0x67cb61b6': ['getChoice()'], + '0xd96a094a': ['buy(uint256)'], + '0x29161820': ['Base(uint256)'], + '0xa5d0bab1': ['buyPartial(uint256,uint256)'], + '0x20bf0c52': ['Derived(uint256)'], + '0x40e58ee5': ['cancel(uint256)'], + '0x13d1aa2e': ['f(uint256,uint256)'], + '0x4579268a': ['getOffer(uint256)'], + '0xe420264a': ['g(uint256)'], + '0x57e871e7': ['blockNumber()'], + '0x4848b1a5': ['setData(uint256,uint256)'], + '0x83324e8c': ['numGroups()'], + '0x0178fe3f': ['getData(uint256)'], + '0x3807ba1b': ['poi()'], + '0x9928811b': ['testBroken()'], + '0x75949c13': ['sendHalf(address)'], + '0x3c7a3aff': ['commit()'], + '0x90b5561d': ['insert(uint256)'], + '0x27121069': ['verify(bytes,uint8,bytes,bytes)'], + '0x3e2729bf': ['isRevocated(bytes)'], + '0x853255cc': ['sum()'], + '0x8cfd8901': ['_incBlock()'], + '0x2feda2fa': ['POI()'], + '0x6a4a6b6e': ['_myAddressHelper()'], + '0x100c8ada': ['setCAmodulus(bytes)'], + '0x5bbfe9b6': ['_myGroupHelper()'], + '0x114d69b2': ['setCRLaddr(address)'], + '0xfd747c0b': ['rsaVerify(bytes,bytes,uint256,bytes)'], + '0x8ac4e1d8': ['TemperatureOracle()'], + '0xfaee13b9': ['set(int8)'], + '0x84734476': ['copyBytes(bytes,uint256,uint256,bytes,uint256)'], + '0x9507d39a': ['get(uint256)'], + '0x9209b3c0': ['getCrtDetails(bytes)'], + '0x17ff0caa': ['WeatherBet(uint256,address,address,address)'], + '0x4664b235': ['bytes32_to_bytes(bytes,bytes,bytes)'], + '0x71dd8862': ['IndexOf()'], + '0xfc687311': ['betOn(int8)'], + '0xa87e7552': ['isValid(bytes,bytes)'], + '0x264c8e9a': ['whatWasTheVal()'], + '0x0b7623ba': ['abs(int8)'], + '0xb4787dc5': ['linkEID(bytes,bytes)'], + '0xbe71248a': ['payWinner()'], + '0x2a095fbe': ['unlinkEID(bytes,bytes,address)'], + '0x511b1df9': ['addr(string)'], + '0x2d077ad0': ['Latch()'], + '0x01984892': ['name(address)'], + '0x616fca9b': ['adopt(address)'], + '0xdf55b41a': ['owner(string)'], + '0x2125b65b': ['transfer(uint32,address,uint224)'], + '0x7f445c24': ['subRegistrar(string)'], + '0xf509b627': ['confirm(address,uint224,uint32,address)'], + '0xdd54a62f': ['content(string)'], + '0xa79f26dc': ['force()'], + '0x20620f37': ['onAuctionEnd(string)'], + '0x89cc5ea8': ['bid(string,address,uint256)'], + '0xb9f37c86': ['Registrar()'], + '0xae999ece': ['reserve(string)'], + '0xff1f7046': ['requiresAuction(string)'], + '0x092b25e9': ['setOwner(string,address)'], + '0x01bd4051': ['disown(string)'], + '0xc47f0027': ['setName(string)'], + '0x9b2ea4bd': ['setAddress(string,address)'], + '0xccf4f413': ['setSubRegistrar(string,address)'], + '0x8bbda7e3': ['setContent(string,bytes)'], + '0x98b1e06a': ['deposit(bytes)'], + '0x1bcf5758': ['getOccupies(uint8)'], + '0xfde9ba41': ['transfer(bytes,address,uint256)'], + '0x0878bc51': ['getAttachesto(uint8)'], + '0x922dd59a': ['icapTransfer(bytes,address,bytes,uint256)'], + '0x4d9e4e22': ['Etheria()'], + '0xe039e4a1': ['getOwner(uint8,uint8)'], + '0xdd34e129': ['PriceTest()'], + '0x7d5fec5a': ['setOwner(uint8,uint8,address)'], + '0xd2d4bd72': ['getCrossRate(bytes,bytes)'], + '0xa55cab95': ['getName(uint8,uint8)'], + '0x93eec1fb': ['setName(uint8,uint8,string)'], + '0xd39eb301': ['getStatus(uint8,uint8)'], + '0x54385526': ['setStatus(uint8,uint8,string)'], + '0x8435be4b': ['getLastFarm(uint8,uint8)'], + '0x90fd53ec': ['farmTile(uint8,uint8,int8)'], + '0x8cae1374': ['editBlock(uint8,uint8,uint256,int8[5])'], + '0xfa93019c': ['getBlocks(uint8,uint8)'], + '0x4ca168cf': ['register(bytes,uint256,address,string,uint256)'], + '0x2ef761d3': ['buyTile(uint8,uint8)'], + '0x6cf9cc58': ['registerResource(bytes,uint256,bytes,string)'], + '0x46c52b1a': ['blockHexCoordsValid(int8,int8)'], + '0xfae9d06d': ['calculateTxFee(uint256,address)'], + '0xbb963c8a': ['transferLibOwnership(bytes,address)'], + '0x8d7108e5': ['isValidLocation(uint8,uint8,int8[5],int8[24])'], + '0xfe029156': ['swap(address,address,uint256,uint256)'], + '0x081bf263': ['isOOB(uint8,uint8)'], + '0x4dd49ab4': ['get(bytes,uint256)'], + '0x9cc9299e': ['killSwap()'], + '0x182db370': ['getWhatHappened()'], + '0x6e353a1d': ['emergencyWithdrawal(address)'], + '0xdf98ef33': ['getResource(bytes,uint256,bytes)'], + '0xf2a75fe4': ['empty()'], + '0xc913b552': ['getVersions(bytes)'], + '0x10c1952f': ['setLocked()'], + '0x0f7d6673': ['Channel()'], + '0x763a738c': ['allNames()'], + '0x2d49ffcd': ['getLocked()'], + '0x423d4ef2': ['createChannel()'], + '0xcb14d93b': ['getHash(bytes,address,uint256)'], + '0x4d1f8c31': ['owner(uint64)'], + '0xadf5e565': ['verify(bytes,address,uint256,uint8,bytes,bytes)'], + '0xe86afde0': ['description(uint64)'], + '0x60c6b3a5': ['claim(bytes,address,uint256,uint8,bytes,bytes)'], + '0x0fdb468f': ['fee(uint64)'], + '0xcebce72d': ['token(uint64)'], + '0xf1c30ec0': ['reclaim(bytes)'], + '0xc0171112': ['timestamp(uint64)'], + '0x7b1cbb13': ['getChannelValue(bytes)'], + '0x1216e771': ['expiration(uint64)'], + '0x29e94503': ['VersionedBlob()'], + '0x5322f0c5': ['getChannelOwner(bytes)'], + '0x1c2f38ff': ['paid(uint64)'], + '0x4c488dac': ['getChannelValidUntil(bytes)'], + '0x9eab5253': ['getMembers()'], + '0x7c79ebce': ['expired(uint64)'], + '0x01da73ff': ['isValidChannel(bytes)'], + '0x541d920c': ['commit(bytes,string)'], + '0x9e66cd38': ['free(uint64)'], + '0x6dd6e87b': ['checkOut(int256)'], + '0x1fb6e99d': ['paymentNeeded(uint64)'], + '0xbb4d7cd1': ['tag(uint256,string)'], + '0x268eb055': ['setDescription(uint64,bytes)'], + '0x856deacf': ['findTag(string)'], + '0x21b36a08': ['setFee(uint64,uint256)'], + '0x86bb7121': ['getBlocksPerRound()'], + '0xb0de1cb7': ['publish(uint64,bytes,uint64)'], + '0x35d129f6': ['untag(string)'], + '0x7ef09476': ['transfer(uint64,address)'], + '0x87bb7ae0': ['getTicketPrice()'], + '0x4c6d1d9e': ['checkOutTag(string)'], + '0x89b8b492': ['read(uint64)'], + '0x67af1c81': ['getRoundIndex()'], + '0x49cbe338': ['tryRead(uint64)'], + '0x358d5dc2': ['getIsCashed(uint256,uint256)'], + '0xb1d51d31': ['pay(uint64,address)'], + '0x6572ae13': ['calculateWinner(uint256,uint256)'], + '0x452fbc41': ['USN(address,address,bytes,uint256,uint256,uint128)'], + '0xdf2f0a4a': ['getDecisionBlockNumber(uint256,uint256)'], + '0x46a2679a': ['getSubpotsCount(uint256)'], + '0x93dafba2': ['getSubpot(uint256)'], + '0x1e62be25': ['Bytes32Passer()'], + '0x930ed251': ['getSavedVar()'], + '0xce5566c5': ['cash(uint256,uint256)'], + '0x6df3edef': ['getSavedBytes()'], + '0x8089d001': ['getHashOfBlock(uint256)'], + '0x812cddf2': ['getSavedString()'], + '0x459f93f7': ['getBuyers(uint256,address)'], + '0x305a762a': ['getTicketsCountByBuyer(uint256,address)'], + '0x28d3ad3f': ['getPot(uint256)'], + '0xbcd3d8ca': ['Collector(address,address,uint256)'], + '0xaf93afdd': [ + 'Shipment(bytes,bytes,bytes,bytes,string,bytes,uint256,uint256,bytes,bytes,uint256,uint256,string,bytes,bytes,bytes)' + ], + '0x7e3faec1': ['GoldTxFeePool(address,address,bytes)'], + '0x7b789b3d': ['agreement(bytes,bytes,bytes)'], + '0xd7f31eb9': ['forward(address,uint256,bytes)'], + '0x5e11544b': ['newPeriod()'], + '0xe2fdcc17': ['escrow()'], + '0x45d27edf': ['forward_method(bytes,address,uint256,bytes)'], + '0x8d227fc0': ['getPeriodInfo()'], + '0xd116c8c4': ['releasePayment()'], + '0x97daa043': ['register(bytes,address,address,uint256,bytes)'], + '0x11e99c22': ['arrival()'], + '0xa7dfc874': ['unregister(bytes,address,uint256,bytes)'], + '0x412664ae': ['sendToken(address,uint256)'], + '0x86c57fcc': ['b32ToBytes(bytes)'], + '0x8c4dd5cd': ['Democracy()'], + '0x66d38203': ['setup(address)'], + '0xe8a1c08f': ['nibbleToChar(uint256)'], + '0x86a50535': ['voteFor(uint256)'], + '0xdbc45228': ['newProposal(address,uint256,bytes,bytes)'], + '0xa99e7e29': ['register(bytes,address)'], + '0x5e44daf3': ['vote(uint256,int256)'], + '0x750e443a': ['voteAgainst(uint256)'], + '0x0d61b519': ['executeProposal(uint256)'], + '0x798974dd': ['getNumProposals()'], + '0x4245b0f7': ['Lottery()'], + '0x11610c25': ['bet()'], + '0x837e7cc6': ['rollDice()'], + '0x714064f3': ['BreakableBond(address,address,uint256)'], + '0x74389991': ['breakit()'], + '0x4cedf74e': ['get_party1()'], + '0xd81a91e9': ['get_party2()'], + '0xa89a4f09': ['creatorBalanceChecker()'], + '0xb9e6f1d9': ['get_amount()'], + '0xa4325485': ['getCreatorBalance()'], + '0xe9a9c1b4': ['get_party1_balance()'], + '0xf363441f': ['getCreatorDotBalance()'], + '0xb8017221': ['get_party2_balance()'], + '0x0109f22e': ['CrowdSale()'], + '0x39aaba25': ['get_status()'], + '0x670c884e': ['setup(address,uint256,uint256,uint256,address)'], + '0x639d57f2': ['testGetBitSuccess()'], + '0x4f76cb02': ['testGetBitFailIndexOOB()'], + '0xfadf87b1': ['testGetBitsSuccess()'], + '0x5a353193': ['KrakenPriceTicker()'], + '0xf24a534e': ['Oracle()'], + '0xc8bb73ef': ['testGetBitsFailIndexOOB()'], + '0x4894e37f': ['__callback(bytes,string,bytes)'], + '0x98596726': ['note(uint224)'], + '0x68e4bd99': ['testSetBitSuccess()'], + '0x69f18967': ['testSetBitFailIndexOOB()'], + '0x2212dbc3': ['get_timestamp()'], + '0x8ba9f354': ['testClearBitSuccess()'], + '0x7057c20d': ['CFD(address)'], + '0x0aa46c12': ['testClearBitFailIndexOOB()'], + '0xd7ef1356': ['best_adjustment(bool)'], + '0xe706918c': ['testToggleBitSuccess()'], + '0x7af30442': ['testToggleBitFailIndexOOB()'], + '0x414053be': ['best_adjustment_for(bool,uint128)'], + '0xdaa21e0e': ['testBitSetSuccess()'], + '0xeef547d7': ['deal_details(uint32)'], + '0x254c91b3': ['testBitNotSetSuccess()'], + '0xb144adfb': ['balance_of(address)'], + '0x2145e36c': ['testBitSetFailIndexOOB()'], + '0xfc63d4fb': ['order(bool,uint32,uint128)'], + '0x6d052f56': ['testBitsSetSuccess()'], + '0xf1cff4b5': ['testBitsNotSetSuccess()'], + '0x1381e400': ['cancel(uint32)'], + '0xf85aefba': ['testBitsSetFailIndexOOB()'], + '0xf41017fc': ['finalize(uint24)'], + '0x42a745cb': ['testBitEqualSuccess()'], + '0x4e6ab570': ['insert_order(address,bool,uint32,uint128)'], + '0xf362d78f': ['testBitNotEqualSuccess()'], + '0xb2d37e95': ['remove_order(uint32)'], + '0x8a120dc9': ['testBitEqualFailIndexOOB()'], + '0x64a4a5d7': ['testBitsEqualSuccess()'], + '0x6f36ce79': ['insert_deal(address,address,uint64,uint128,uint32)'], + '0x74087040': ['testBitsNotEqualSuccess()'], + '0x10e89b22': ['remove_deal(uint32)'], + '0xfbffb355': ['testBitsEqualFailIndexOOB()'], + '0x1e44c112': ['find_strike(uint64,uint32,uint32)'], + '0x2b785960': ['testBitAndSuccess()'], + '0xc388cca6': ['testBitAndFailIndexOOB()'], + '0xbac1e2e0': ['testBitsAndSuccess()'], + '0xd588acc4': ['claimMiningReward()'], + '0xda2b7416': ['testBitsAndFailIndexOOB()'], + '0xa1616429': ['testBitOrSuccess()'], + '0xfd83f3e3': ['QueueUserMayBeDeliveryDroneCotnrol()'], + '0x91e8d3dc': ['testBitOrFailIndexOOB()'], + '0x4ca1fad8': ['addRequest(uint256)'], + '0xec0f1025': ['testBitsOrSuccess()'], + '0xe4690a0b': ['popRequest()'], + '0x2581c674': ['testBitsOrFailIndexOOB()'], + '0xab91c7b0': ['queueLength()'], + '0x31be6985': ['testBitXorSuccess()'], + '0xa268b332': ['testBitXorFailIndexOOB()'], + '0xe044c2de': [ + 'newLoan(bytes,address,uint256,uint256,uint256,uint256,uint256,uint256)' + ], + '0x622e88cb': ['testBitsXorSuccess()'], + '0x8e46fbb2': ['testBitsXorFailIndexOOB()'], + '0xc1cbbca7': ['contribute(uint256)'], + '0x278ecde1': ['refund(uint256)'], + '0xe2f8a017': ['payInstallment(uint256)'], + '0xbb510a77': ['createChannel(address,uint256)'], + '0xacf8bf2a': ['channelCount()'], + '0xd7bc23af': ['newParameters(int256,uint256,uint256,uint256)'], + '0x1b855044': ['getHash(uint256,uint256)'], + '0x65093661': ['newCommunity(address)'], + '0xe22b0c46': ['verify(uint256,uint256,uint8,bytes,bytes)'], + '0x5f1231ea': ['getMemberInfo(address)'], + '0x23add736': ['claim(uint256,uint256,uint8,bytes,bytes)'], + '0x3dd7c1b9': ['newProduct(string,string,uint256,uint256)'], + '0x79a85e6c': ['getProductInfo(uint256)'], + '0x2dabbeed': ['reclaim(uint256)'], + '0xa0440426': ['purchaseProduct(uint256,uint256)'], + '0xb7a97a2b': ['isValidChannel(uint256)'], + '0xe7d50e5c': ['FarmShare()'], + '0x3e0a51b4': ['TweetAccount()'], + '0xb6db75a0': ['isAdmin()'], + '0x4a23dc52': ['FileStore()'], + '0xfb46d4c5': ['tweet(string)'], + '0x5aebfd14': ['createFile(bytes)'], + '0xc3ad5ecb': ['getTweet(uint256)'], + '0xc5958bda': ['removeFile(bytes)'], + '0xae978f08': ['getLatestTweet()'], + '0x3d8e2947': ['getFileAddress(bytes)'], + '0xe4c2db06': ['getPreviousFile(bytes)'], + '0x0c4f65bd': ['getOwnerAddress()'], + '0xca77ab8a': ['getNextFile(bytes)'], + '0xca7dc5b1': ['getNumberOfTweets()'], + '0xdc63a62c': ['getFileListHead()'], + '0x95671958': ['getFileListTail()'], + '0x5c3e426c': ['adminRetrieveDonations(address)'], + '0x7d60e343': ['getFileListSize()'], + '0x3e450fff': ['adminDeleteAccount()'], + '0xe4360fc8': ['getFileListElement(bytes)'], + '0x492b67ea': ['Etherdoc()'], + '0x3f77b560': ['newDocument(bytes)'], + '0x3448c7d6': ['createHistory(bytes,address,address)'], + '0x0b80f8d3': ['invmod(uint256,uint256)'], + '0x2f6ae467': ['transferDocument(bytes,address)'], + '0x783ce458': ['expmod(uint256,uint256,uint256)'], + '0xe4547f98': ['documentExists(bytes)'], + '0xeccb15bc': ['SatPosition(int256,int256)'], + '0xf6458c6a': ['toZ1(uint256[3],uint256)'], + '0x3f9b250a': ['getDocument(uint256)'], + '0xafc4a982': ['PathCost(uint16,uint32)'], + '0xc36af460': ['getLatest()'], + '0x306df22d': ['GPSDestination(int256,int256,uint256)'], + '0xd44aadf7': ['initROS()'], + '0x54ae8492': ['CustodialForward()'], + '0x4a00a522': ['homebase(int256,int256)'], + '0x677913e9': ['setAmount(int32)'], + '0x418cf199': ['setEstimateCost(uint256,uint256)'], + '0x739f888c': ['setNewEstimate(int256,int256)'], + '0xc028df06': ['offer()'], + '0xe816a515': ['takeFlight()'], + '0xa6f2ae3a': ['buy()'], + '0xd810f298': ['computeSettlementAmount()'], + '0x48a0d754': ['available()'], + '0xb595181f': ['ShapeshiftBot()'], + '0xf27197ab': ['getIsAvailable()'], + '0xcb2b9031': ['addressToBytes(address,address)'], + '0x883ba26b': ['getIsSettled()'], + '0x504ac982': ['transfer(string,string)'], + '0x60e519c0': ['computeMarginAmount()'], + '0x8a9ffb90': ['transfer(string,string,bool)'], + '0x468f02d2': ['getUnderlyingPrice()'], + '0x2facc4e8': ['depositGovernance(uint256,address)'], + '0xf29617da': ['registrationDeposit(address)'], + '0x1d834a1b': ['insert(uint256,uint256)'], + '0x9a863892': ['NewProposal(uint256)'], + '0xe2233ada': ['smartDoor(address[])'], + '0x3106fea0': ['voteOnProposal(uint256,bool,uint256)'], + '0x22ebb3ac': ['DieselPricePeg()'], + '0xdb0e127a': ['openDoor()'], + '0x0965bf7d': ['processProposals()'], + '0x82ab890a': ['update(uint256)'], + '0xa05e822a': ['howManyOwners()'], + '0xa0e67e2b': ['getOwners()'], + '0x67546967': ['EthBtcEscrow()'], + '0x63052d82': ['getOwnersIndex(address)'], + '0x6cf761d4': ['getMinConfirmationsByAddr(address)'], + '0x97297467': ['checkAndVerify(bytes)'], + '0x9c43d950': ['registration(uint256,uint256,uint256)'], + '0xe68d3ae3': ['escrow(uint256,string,address,uint256)'], + '0xeece1e1f': ['scheduleShuffling()'], + '0x35ee2783': ['Alarm()'], + '0x48519189': ['MonedaAlcala(string,string)'], + '0xbd9335c0': ['scheduleHangouts()'], + '0x7143059f': ['getParticipant(address)'], + '0x65b1fdf4': ['scheduleIssuePOIs()'], + '0xb3c25835': ['addUser(address,string,string,uint256)'], + '0xb37217a4': ['getRandomNumber(uint256)'], + '0x47274dbe': ['disableUser(address,address)'], + '0xdcf73856': ['generateGroups()'], + '0x2090cf8b': ['consultBalance(address)'], + '0xc3d345c4': ['getHangoutAddress()'], + '0x9f8a13d7': ['isActive(address)'], + '0x4e23a144': ['fundUser(address,uint256)'], + '0x34e8980f': ['bootUpHangouts()'], + '0xfc89aff6': ['submitVerifiedUsers(address[])'], + '0x96ed10a4': ['issuePOIs()'], + '0x92b4bb50': ['rps()'], + '0x8e7ea5b2': ['getWinner()'], + '0x718e6302': ['play(string)'], + '0x4c738909': ['getMyBalance()'], + '0x79b0797c': ['AmIPlayer1()'], + '0x805210b7': ['AmIPlayer2()'], + '0x452d44dc': ['checkBothNotNull()'], + '0x4162169f': ['dao()'], + '0xce8b7151': ['isHF()'], + '0x8cdfb1e6': ['transferIfHF(address)'], + '0xc3b8bfe5': ['transferIfNoHF(address)'], + '0x82afd23b': ['isActive(uint256)'], + '0xc41a360a': ['getOwner(uint256)'], + '0xd05c78da': ['safeMul(uint256,uint256)'], + '0xd6febde8': ['buy(uint256,uint256)'], + '0x598647f8': ['bid(uint256,uint256)'], + '0x379607f5': ['claim(uint256)'], + '0x2ac9bf09': ['bid(uint256,uint256,uint256)'], + '0x1df47aad': ['ReplayProtection()'], + '0xc42cd8cf': ['etherSplit(address,address)'], + '0x9f5f7c7f': ['tokenSplit(address,address,address,uint256)'], + '0x2c215998': ['updateStatus(string)'], + '0x30ccebb5': ['getStatus(address)'], + '0xb46300ec': ['send()'], + '0x92d282c1': ['Send()'], + '0x5323c6cf': ['calcCostsBuying(bytes,uint256,uint256[],uint8,uint256)'], + '0x532e7e6a': ['calcEarningsSelling(bytes,uint256,uint256[],uint8,uint256)'], + '0x46a1d95f': ['closeMarket(bytes)'], + '0x4b031d0f': ['shortSellShares(bytes,uint8,uint256,uint256)'], + '0x45c41478': ['getMarkets(bytes,address)'], + '0x1c879c47': ['getMarketHashes(bytes)'], + '0x9948e493': ['calcMarketFee(bytes,uint256)'], + '0xf7a0fa0a': ['getShareDistribution(bytes)'], + '0xd0315658': ['getShareDistributionWithTimestamp(bytes)'], + '0xef04fdb7': ['buyShares(bytes,uint8,uint256,uint256)'], + '0x86723215': ['createMarket(bytes,uint256,uint256,address)'], + '0x55ba343f': ['getMarket(bytes)'], + '0x4401ff5c': ['sellShares(bytes,uint8,uint256,uint256)'], + '0xdf6c13c3': ['getMinFunding()'], + '0x9431f5f0': ['withdrawFees(bytes)'], + '0x43703b0e': ['getEventData(bytes)'], + '0x632f0ba6': ['descriptionHashes(bytes)'], + '0x5e58f141': ['shares(address,bytes,int256)'], + '0xdb5b4183': ['oracleOutcomes(bytes,address)'], + '0x3d69b403': ['isOutcomeSet(bytes)'], + '0xea4ba8eb': ['getOutcome(bytes)'], + '0xbbd8b602': ['getOracleOutcomes(bytes,address[])'], + '0x9ec32d45': ['challengeWinningOutcome(bytes,uint16)'], + '0x41095b60': ['voteForUltimateOutcome(bytes,uint16)'], + '0x8f6f988c': ['setUltimateOutcome(bytes)'], + '0x0968f264': ['withdraw(bytes)'], + '0x1397fdbd': ['getShares(address,bytes,int256[])'], + '0x45ee49b9': ['getUltimateOutcomes(bytes)'], + '0xc90d080a': ['registerEvent(bytes)'], + '0xc0ae6a3a': ['ultimateOutcomes(bytes)'], + '0xc2038560': ['setOutcome(bytes,bytes)'], + '0x8204ecdd': ['getFee(bytes)'], + '0xffcf21a9': ['eventOracles(bytes,uint256)'], + '0x08bf2d0d': ['getOrderBook(uint256,uint256)'], + '0x0e0f55d0': ['RewardOrder(uint256,uint256)'], + '0x0e97cfdf': ['placeOrder(uint256,uint256,uint256)'], + '0x29ef56b1': ['getAskOrderBookStats()'], + '0x3bed33ce': ['withdrawEther(uint256)'], + '0x50baa622': ['withdrawToken(uint256)'], + '0x512f1e64': ['orderBookLength()'], + '0x8ea98117': ['setCoordinator(address)'], + '0x9824425a': ['takeOrder(uint256,uint256,uint256,uint256)'], + '0x98ea5fca': ['depositEther()'], + '0xa2f16d80': ['dexWithdrawCollectedFees()'], + '0xb6ed0632': ['cancelOrder(uint256,uint256)'], + '0xe71264fa': ['addNewTokens(uint256)'], + '0xf1e4a540': ['unsetCoordinator()'], + '0xfe992c98': ['balanceOfAll(address)'], + '0x069d6d1c': ['closeOrder(uint256)'], + '0x070a888f': ['updateRewardDuration(uint256)'], + '0x09405164': ['getOpenCandidates()'], + '0x09a69f57': ['getRewardAmount()'], + '0x27cca148': ['lastClaimedBlock()'], + '0x942b90d3': ['getRewardTable()'], + '0xa9eed530': ['reduceOrderQty(uint256,uint256)'], + '0xc67d376d': ['getClosedCandidates()'], + '0xd3f297d6': ['claimLiquidityReward()'], + '0xfcc11241': ['addOrder(uint256,uint256,uint256,uint256,uint256,uint8)'], + '0x5829d310': ['entries(int256)'], + '0x8f9df278': [ + 'newEntry(int256,bool,uint256,int256,string,bytes32,address,uint256[])' + ], + '0x031d973e': ['closeMarket(bytes32)'], + '0x16181bb7': ['shortSellShares(bytes32,uint8,uint256,uint256)'], + '0x5aa97eeb': ['getMarkets(bytes32[],address)'], + '0x674cc1f5': ['getMarketHashes(bytes32[])'], + '0x6da84ec0': ['calcMarketFee(bytes32,uint256)'], + '0x929e626e': ['getShareDistribution(bytes32)'], + '0xa0bde7e8': ['getShareDistributionWithTimestamp(bytes32)'], + '0xbbd4f854': ['buyShares(bytes32,uint8,uint256,uint256)'], + '0xc1fd4339': ['createMarket(bytes32,uint256,uint256,address)'], + '0xc3c95c7b': ['getMarket(bytes32)'], + '0xdb833e3a': ['sellShares(bytes32,uint8,uint256,uint256)'], + '0xebb71194': ['withdrawFees(bytes32)'], + '0x07d5b826': ['buyAllOutcomes(bytes32,uint256)'], + '0x15e812ad': ['getBaseFee()'], + '0x1934d55a': ['isPermanentlyApproved(address,address)'], + '0x1d007f5f': ['changeDAO(address)'], + '0x1f0c1e0c': ['getEventTokenAddress(bytes32,uint256)'], + '0x3983d5c4': ['calcBaseFee(uint256)'], + '0x4025b293': ['redeemAllOutcomes(bytes32,uint256)'], + '0x428d64bd': ['getShares(address,bytes32[])'], + '0x481b659d': ['permitPermanentApproval(address)'], + '0x57bcccb6': ['revokePermanentApproval(address)'], + '0x8c172fa2': ['getEvent(bytes32)'], + '0x9ba5b4e9': ['getEventHashes(bytes32[])'], + '0xa4a7cf5c': ['redeemWinnings(bytes32)'], + '0xb11e3b82': [ + 'createEvent(bytes32,bool,int256,int256,uint8,address,address,bytes32[])' + ], + '0xc10dd4c6': ['getEvents(bytes32[],address)'], + '0xc51cf179': ['calcBaseFeeForShares(uint256)'], + '0xeff6be2f': ['changeBaseFee(uint256)'], + '0x13fc6ac2': ['getEventData(bytes32)'], + '0x51017702': ['isOutcomeSet(bytes32)'], + '0x5d1a3b82': ['getOutcome(bytes32)'], + '0xc1b06513': ['registerEvent(bytes32[])'], + '0xc91d7e9c': ['getFee(bytes32[])'], + '0x3ced516c': ['descriptionHashes(bytes32)'], + '0x488b3538': ['shares(address,bytes32,int256)'], + '0x4ad07b0e': ['oracleOutcomes(bytes32,address)'], + '0x659fb968': ['getOracleOutcomes(bytes32[],address[])'], + '0x6b1e564a': ['challengeWinningOutcome(bytes32,uint16)'], + '0x7b395487': ['voteForUltimateOutcome(bytes32,uint16)'], + '0x8aa6f1b1': ['setUltimateOutcome(bytes32)'], + '0x8e19899e': ['withdraw(bytes32)'], + '0x98f3b81a': ['getShares(address,bytes32[],int256[])'], + '0xa0ec4e09': ['getUltimateOutcomes(bytes32[])'], + '0xc25e6908': ['ultimateOutcomes(bytes32)'], + '0xc71e48d6': ['setOutcome(bytes32,bytes32[])'], + '0xfcf0f55b': ['eventOracles(bytes32,uint256)'], + '0x01991313': ['scheduleCall(address,bytes4,uint256)'], + '0x480b70bd': ['scheduleCall(address,bytes4,uint256,uint256)'], + '0x049ae734': ['scheduleCall(address,bytes4,uint256,uint256,uint8)'], + '0x68402460': ['scheduleCall(address,bytes4,uint256,uint256,uint8,uint256)'], + '0x8b676ae8': [ + 'scheduleCall(address,bytes4,uint256,uint256,uint8,uint256,uint256)' + ], + '0x30fd300f': ['registerBytes32(address,bytes32)'], + '0x741e2345': [ + 'registerMany(address,uint256,int256,uint256,bytes20,address,bytes)' + ], + '0x73b55eaf': ['registerData(address,int256,bytes32,address)'], + '0xc2b12a73': ['setBytes32(bytes32)'], + '0xf2da67db': ['setMany(uint256,int256,uint256,bytes20,address,bytes)'], + '0x0e850239': ['scheduleCall(bytes4,bytes)'], + '0x4db3da83': ['scheduleCall(bytes4)'], + '0x373a1bc3': ['scheduleCall(address,bytes4)'], + '0x3c2c21a0': ['scheduleCall(address,uint256,bytes4)'], + '0xa1c0539d': ['scheduleCall(address,bytes4,bytes)'], + '0x795b9a6f': ['scheduleCall(address,bytes4,uint256,bytes)'], + '0xc43d0575': ['scheduleCall(bytes4,uint256)'], + '0x3d9ce89b': ['scheduleCall(bytes4,bytes,uint256)'], + '0x48f05187': ['scheduleCall(address,bytes4,bytes,uint256)'], + '0x346cabbc': ['scheduleCall(address,bytes4,uint256,bytes,uint256)'], + '0x8c0e156d': ['scheduleCall(bytes4,uint256,uint256)'], + '0x5a9f2def': ['scheduleCall(bytes4,bytes,uint256,uint256)'], + '0x9772c982': ['scheduleCall(address,bytes4,bytes,uint256,uint256)'], + '0x3a9e7433': ['scheduleCall(bytes4,uint256,uint256,uint8)'], + '0x64ee49fe': ['scheduleCall(address,uint256,bytes4,uint256,uint256,uint8)'], + '0xee77fe86': ['scheduleCall(address,bytes4,bytes,uint256,uint256,uint8)'], + '0xe29fb547': ['scheduleCall(bytes4,uint256,uint256,uint8,uint256)'], + '0x03d22885': [ + 'scheduleCall(address,uint256,bytes4,uint256,uint256,uint8,uint256)' + ], + '0xb549793d': ['scheduleCall(bytes4,bytes,uint256,uint256,uint8,uint256)'], + '0x7b55c8b5': ['scheduleCall(address,bytes4,bytes,uint8,uint256[4])'], + '0x4c471cde': [ + 'scheduleCall(address,bytes4,bytes,uint256,uint256,uint8,uint256)' + ], + '0x938c4307': [ + 'scheduleCall(bytes4,bytes,uint16,uint8,uint256,uint256,uint256,uint256,uint256)' + ], + '0x0ce46c43': ['scheduleCall(address,bytes4,bytes,uint16,uint8,uint256[5])'], + '0x528eedcb': ['sendSafe(address,address,uint256)'], + '0x2812f8b8': [ + 'FutureCall(address,uint256,uint16,address,bytes4,bytes,uint256,uint256,uint256)' + ], + '0xcdda62ad': [ + 'FutureBlockCall(address,uint256,uint8,address,bytes4,bytes,uint256,uint256,uint16,uint256,uint256)' + ], + '0xc976bbbb': ['_compare(int256,bytes2,int256)'], + '0x9f2ce678': ['vote(bytes32,bool)'], + '0x318a3fee': ['relayTx(bytes,int256,int256[],int256,int256)'], + '0xa06db7dc': ['gracePeriod()'], + '0xc6502da8': ['basePayment()'], + '0x625cc465': ['baseDonation()'], + '0x938b5f32': ['origin()'], + '0xeaa37394': ['create(bytes,bytes32,bool,bool,bool,bool,bool)'], + '0xf6469342': ['_setPackedBlockNumber(bytes32,uint256)'], + '0xf3e84cf3': ['createNewRevision(bytes32,bytes)'], + '0xf0cb556c': ['updateLatestRevision(bytes32,bytes)'], + '0x37664643': ['retractLatestRevision(bytes32)'], + '0x9b619d3b': ['_deleteAllPackedRevisionBlockNumbers(bytes32)'], + '0x2bf1f9da': ['restart(bytes32,bytes)'], + '0x117b4705': ['retract(bytes32)'], + '0x0eb8ed07': ['transferEnable(bytes32)'], + '0xaaac50bd': ['transferDisable(bytes32)'], + '0x79ce9fac': ['transfer(bytes32,address)'], + '0xd93e7573': ['disown(bytes32)'], + '0x89ced196': ['setNotUpdatable(bytes32)'], + '0xfe8b6642': ['setEnforceRevisions(bytes32)'], + '0x0d244d68': ['setNotRetractable(bytes32)'], + '0xb7d454a4': ['setNotTransferable(bytes32)'], + '0x4788cabf': ['getContractId()'], + '0x737c8ea1': ['_getRevisionBlockNumber(bytes32,uint256)'], + '0x9070b18d': ['_getAllRevisionBlockNumbers(bytes32)'], + '0x7a02dc06': ['getInfo(bytes32)'], + '0xdeb931a2': ['getOwner(bytes32)'], + '0x64228857': ['getRevisionCount(bytes32)'], + '0xa95d017d': ['getRevisionBlockNumber(bytes32,uint256)'], + '0xb7dd1d17': ['getAllRevisionBlockNumbers(bytes32)'], + '0x49437210': ['getUpdatable(bytes32)'], + '0x0b6fcdb0': ['getEnforceRevisions(bytes32)'], + '0x331a72d1': ['getRetractable(bytes32)'], + '0xf0da84f8': ['getTransferable(bytes32)'], + '0x1d82e9c7': ['EXTRA_GAS()'], + '0x964c836c': ['receiveExecutionNotification()'], + '0xc262df45': ['isKnownRequest(address,address)'], + '0x7fee4ecb': ['GAS_PER_DEPTH()'], + '0x07ad9ecb': ['safeSend(address,uint256)'], + '0xeacc5b3b': ['safeSend(address,uint256,uint256)'], + '0x1a26ed1c': ['validateReservedWindowSize(uint256,uint256)'], + '0x2e898ddc': ['validateTemporalUnit(uint256)'], + '0xb3aaa277': [ + 'validate(address[4],address,uint256[11],uint256,bytes,uint256)' + ], + '0xc45b415e': ['createRequest(address[4],address,uint256[11],uint256,bytes)'], + '0xf00e8651': ['createRequest(address[2],address,uint256[11],uint256,bytes)'], + '0x17a601b5': ['MAX_STACK_DEPTH_REQUIREMENT()'], + '0x3121369d': ['validateRequiredStackDepth(uint256)'], + '0xb5f5962a': ['CALL_GAS_CEILING(uint256)'], + '0xf4c5ab7c': ['validateCallGas(uint256,uint256)'], + '0xd7504385': ['validateToAddress(address)'], + '0x610d5de8': ['validateEndowment(uint256,uint256,uint256,uint256,uint256)'], + '0xcd9a3c98': ['any(bool[7])'], + '0xf1fe42b8': [ + 'TransactionRequest(address[3],address,uint256[11],uint256,bytes)' + ], + '0x00a676f9': ['getExists(bytes32)'], + '0xf42aa287': ['getBlobStore(bytes12)'], + '0x8f420866': ['DEFAULT_SEND_GAS()'], + '0xa126c5df': ['GAS_TO_AUTHORIZE_EXECUTION()'], + '0xbd35d570': ['GAS_TO_COMPLETE_EXECUTION()'], + '0xf6bd5893': ['getGas(uint256)'], + '0x606deecd': ['requestData()'], + '0xf9909915': ['bulkStoreHeader(bytes,int256,bytes,int256)'], + '0x129484b6': [ + 'changeFeeRecipient(int256,int256,int256,int256,int256,int256)' + ], + '0xca0c1e62': [ + 'computeMerkle(int256,int256,int256[],int256,int256,int256[])' + ], + '0x752d349c': ['depthCheck(int256,int256)'], + '0x157f8f51': ['feePaid(int256,int256,int256,int256)'], + '0x7ca823d5': ['getAverageChainWork()'], + '0x9a15f4f3': ['getBlockHeader(int256,int256)'], + '0x2c181929': ['getChainWork()'], + '0xfa14df6b': ['getChangeRecipientFee()'], + '0xc018d0e6': ['getFeeAmount(int256,int256)'], + '0x16e27349': ['getFeeRecipient(int256,int256)'], + '0xace51abc': [ + 'helperVerifyHash__(uint256,int256,int256[],int256,uint256,int256,int256[],int256)' + ], + '0x11400d8e': ['priv_fastGetBlockHash__(int256,int256)'], + '0x3c2e7d54': ['priv_inMainChain__(int256,int256)'], + '0xecb0256b': [ + 'relayTx(bytes,int256,int256[],int256,int256,bytes,int256,int256[],int256,int256)' + ], + '0xfae8f9a2': ['setInitialParent(int256,int256,int256,int256,int256,int256)'], + '0x6e173a7f': ['storeBlockHeader(bytes,bytes)'], + '0x3af75ee1': ['storeBlockWithFee(bytes,int256,bytes,int256)'], + '0xfad9bf9e': [ + 'storeBlockWithFeeAndRecipient(bytes,int256,int256,bytes,int256,int256)' + ], + '0x05a5b8c6': [ + 'verifyTx(bytes,int256,int256[],int256,bytes,int256,int256[],int256)' + ], + '0x9a89ad65': ['within6Confirms(int256,int256)'], + '0x362af076': ['createRequest(address[3],address,uint256[11],uint256,bytes)'], + '0x09861b81': ['flooredSub(uint256,uint256)'], + '0x3dd297da': ['safeMultiply(uint256,uint256)'], + '0x88102583': ['safeCastSigned(uint256)'], + '0x592685d5': ['getWindowStart(address,address)'], + '0xbf2e694f': ['getPreviousRequest(address,address)'], + '0x1acb2719': ['getNextRequest(address,address)'], + '0x09d33f1d': ['addRequest(address,uint256)'], + '0xac8d6030': ['removeRequest(address)'], + '0xb15dcc25': ['query(address,bytes2,uint256)'], + '0x17e1b09b': ['minimumDeposit(uint256)'], + '0x8fbc3ecd': ['BUFFER()'], + '0x3f0ec70b': ['RequestFactory(address)'], + '0xfb87d5ea': [ + 'TransactionRequest(address[4],address,uint256[11],uint256,bytes)' + ], + '0xb311ee0c': ['refundClaimDeposit()'], + '0x8dd8596c': ['sendDonation()'], + '0x6720ceb1': ['sendPayment()'], + '0x6949a058': ['sendOwnerEther()'], + '0x66671c71': ['BaseScheduler(address,address)'], + '0xbf8c50ff': ['scheduleTransaction()'], + '0x93c166ec': ['computeEndowment(uint256,uint256,uint256,uint256)'], + '0xfff78f9c': ['doThrow()'], + '0xf0586f0d': ['doThrow(bool)'], + '0x2667f407': ['__proxy(address,bytes)'], + '0xc3fa5f93': ['BlockScheduler(address,address)'], + '0xb0bcc610': ['scheduleTransaction(address)'], + '0xb8f71f26': ['scheduleTransaction(uint256,address)'], + '0x30c0f8d6': ['scheduleTransaction(address,bytes)'], + '0xc0eb2325': ['scheduleTransaction(address,bytes,uint256)'], + '0x4d5b080c': ['scheduleTransaction(uint256,address,uint256)'], + '0xb03260be': ['scheduleTransaction(uint256,address,bytes)'], + '0xcf4a1612': ['scheduleTransaction(uint256,address,bytes,uint256)'], + '0xed4b1d0d': ['scheduleTransaction(uint256)'], + '0x57e2880d': ['scheduleTransaction(uint256,uint256)'], + '0xcf158fe9': ['scheduleTransaction(uint256,uint256,uint256)'], + '0xf0a78538': ['scheduleTransaction(uint256,bytes)'], + '0xe33c7ae2': ['scheduleTransaction(uint256,uint256,bytes)'], + '0x1099d3ec': ['scheduleTransaction(uint256,uint256,uint256,bytes)'], + '0x447cd682': ['scheduleTransaction(address,uint256)'], + '0x02e8d8c0': ['scheduleTransaction(address,uint256,uint256)'], + '0xd0549602': ['scheduleTransaction(address,uint256,uint256,uint256)'], + '0x44dd4b5e': ['scheduleTransaction(address,uint256,bytes)'], + '0xb67fabdf': ['scheduleTransaction(address,uint256,uint256,bytes)'], + '0xc9296d14': ['scheduleTransaction(address,uint256,uint256,uint256,bytes)'], + '0x314e0fb6': ['scheduleTransaction(address,bytes,uint256[3],uint256)'], + '0xceba30b5': ['scheduleTransaction(address,bytes,uint256[4],uint256)'], + '0xd4c2b6b1': ['scheduleTransaction(address,bytes,uint256[5],uint256)'], + '0xa42e36c6': ['scheduleTransaction(address,bytes,uint8,uint256[5],uint256)'], + '0x3c894475': ['scheduleTransaction(address,bytes,uint8,uint256[6],uint256)'], + '0x4ed4831a': ['all(bool[7])'], + '0xc5f310c0': ['register(bytes12)'], + '0x266710ca': ['manualUpdateBalances_only_Dev()'], + '0x2e0ef395': ['voteOnNewEntryFees_only_VIP(uint8)'], + '0x33ce7787': ['transferInvestorAccount(address,address)'], + '0x402e6230': ['getTotalGambles()'], + '0x580bdf3c': ['disableBetting_only_Dev()'], + '0x6ad50ed4': ['investmentEntryInfos()'], + '0x750cae6a': ['enableBetting_only_Dev()'], + '0x7c9cd7df': ['changeDeveloper_only_Dev(address)'], + '0xbb84d362': ['splitProfitVIP_only_Dev()'], + '0xc7144269': [ + 'changeSettings_only_Dev(uint256,uint256,uint256,uint256,uint16,uint256,uint256,uint256,uint8,uint8)' + ], + '0xe56c8552': ['spinTheWheel(address)'], + '0x433836dc': ['scheduleTransaction(address,bytes,uint8,uint256[3],uint256)'], + '0x9341231c': ['sendOrThrow(address,uint256)'], + '0x1d49e081': ['EXECUTE_EXTRA_GAS()'], + '0xd2531590': ['CANCEL_EXTRA_GAS()'], + '0xad8ed335': ['__proxy(address)'], + '0x9af605cb': ['__proxy(address,bytes,uint256)'], + '0xf10ae2ab': ['__dig_then_proxy(uint256,address,bytes)'], + '0x9a35f886': ['__dig_then_proxy(uint256)'], + '0x7cbcc254': ['__reset__()'], + '0x6aaba012': ['ErrorGenerator()'], + '0x40a3d246': ['toggle()'], + '0x51582ef3': ['sendProxyTransaction(address,uint256,uint256,bytes)'], + '0x7b632c41': ['TimestampScheduler(address,address)'], + '0xb69c0896': ['BaseScheduler(address,address,uint256)'], + '0x30aceb89': [ + 'validateRequestParams(address[3],address,uint256[11],uint256,bytes,uint256)' + ], + '0x15abc160': [ + 'createValidatedRequest(address[3],address,uint256[11],uint256,bytes)' + ], + '0x316b08a0': ['scheduleTransaction(address,bytes,uint256[7],uint256)'], + '0xd96d7ea2': ['PRE_EXECUTION_GAS()'], + '0x45104b16': ['EXECUTION_GAS_OVERHEAD()'], + '0xc7e67360': ['GAS_BUFFER()'], + '0x5ee345e4': [ + 'computeEndowment(uint256,uint256,uint256,uint256,uint256,uint256)' + ], + '0x27960c5f': [ + 'validateEndowment(uint256,uint256,uint256,uint256,uint256,uint256,uint256)' + ], + '0x81baf820': ['BlockScheduler(address)'], + '0xba8661a2': ['TimestampScheduler(address)'], + '0x6b9b1006': ['TransactionRecorder()'], + '0x043753ba': ['makeDecision(uint256,bool)'], + '0xcd2cdd5b': ['claimOwnershi()'], + '0x1ac61e8c': ['testBlobCreate()'], + '0x741273d6': ['testThrowRegisterContractAgain()'], + '0x59e2d30e': ['testThrowBlobStoreNotRegistered()'], + '0xfa3f1e99': ['testBlobStoreRegistered()'], + '0x29e30910': ['testThrowCreateExistingNonce()'], + '0xd62d3115': ['testCreate()'], + '0xa5dfee67': ['testThrowsCreateNewRevisionNotUpdatable()'], + '0x85b73d3c': ['testCreateNewRevision()'], + '0x5f0edfb8': ['create(bytes,bytes32,bytes1)'], + '0x2551858e': ['getFlags(bytes32)'], + '0x8d375da2': ['testMakeItFail()'], + '0xe597f402': ['create(bytes1,bytes32,bytes)'], + '0x7fefde53': ['WillRegistry()'], + '0x337b1cf9': ['setIpfsHash(bytes)'], + '0xd0b52156': ['getIpfsHash(address,address)'], + '0x5b37e150': ['create(bytes32,bytes)'], + '0x338a1379': ['_setPackedBlockNumber(bytes20,uint256)'], + '0xa84c5330': ['createNewRevision(bytes20,bytes)'], + '0x9e65c7e5': ['updateLatestRevision(bytes20,bytes)'], + '0xa7e93e87': ['retractLatestRevision(bytes20)'], + '0x5ccd2f9b': ['_deleteAllPackedRevisionBlockNumbers(bytes20)'], + '0xe0a70811': ['restart(bytes20,bytes)'], + '0xcf7315c6': ['retract(bytes20)'], + '0x12511c14': ['transferEnable(bytes20)'], + '0x47bdb7f4': ['transferDisable(bytes20)'], + '0xb06df18e': ['transfer(bytes20,address)'], + '0xd6ca8ccb': ['disown(bytes20)'], + '0xd0c24e93': ['setNotUpdatable(bytes20)'], + '0x9243e088': ['setEnforceRevisions(bytes20)'], + '0x976b01c0': ['setNotRetractable(bytes20)'], + '0xb971b4e5': ['setNotTransferable(bytes20)'], + '0x08b7c13b': ['getExists(bytes20)'], + '0xfb47a067': ['_getRevisionBlockNumber(bytes20,uint256)'], + '0xec035393': ['_getAllRevisionBlockNumbers(bytes20)'], + '0xba15e52e': ['getInfo(bytes20)'], + '0x01fd89a4': ['getFlags(bytes20)'], + '0x3df91162': ['getUpdatable(bytes20)'], + '0xdba1ac3d': ['getEnforceRevisions(bytes20)'], + '0x3c335b0e': ['getRetractable(bytes20)'], + '0xaa5d4719': ['getTransferable(bytes20)'], + '0xe487eb58': ['getOwner(bytes20)'], + '0x3ef87414': ['getRevisionCount(bytes20)'], + '0x74f8d96e': ['getRevisionBlockNumber(bytes20,uint256)'], + '0x22057bc7': ['getAllRevisionBlockNumbers(bytes20)'], + '0x13137731': ['testThrowsUpdateLatestRevisionNotUpdatable()'], + '0x2eb5c61f': ['testThrowsUpdateLatestRevisionEnforceRevisions()'], + '0x1fb2f2a0': ['testUpdateLatestRevision()'], + '0xe82f7dd4': ['testThrowsRetractLatestRevisionNotUpdatable()'], + '0x8e1ffb19': ['testThrowsRetractLatestRevisionEnforceRevisions()'], + '0xe0cfc05c': [ + 'testThrowsRetractLatestRevisionDoesntHaveAdditionalRevisions()' + ], + '0x40695625': ['testRetractLatestRevision()'], + '0x1b769e74': ['testThrowsRestartNotUpdatable()'], + '0x5292c1a9': ['testThrowsRestartEnforceRevisions()'], + '0x465e759b': ['testRestart()'], + '0xcaab0acc': ['testThrowCreateRetracted()'], + '0xd96e5565': ['testThrowsRetractNotRetractable()'], + '0x0af4626d': ['testRetract()'], + '0x804e11dc': ['testThrowsDisownNotTransferable()'], + '0xda5c0a7c': ['testDisown()'], + '0xad544dcb': ['testSetNotUpdatable()'], + '0xee0dc478': ['testSetEnforceRevisions()'], + '0xac3e6b2f': ['testSetNotRetractable()'], + '0xa039e3c7': ['testSetNotTransferable()'], + '0x30a24abd': ['create(bytes4,bytes)'], + '0x446fbcd1': ['CredSign()'], + '0x2e06c756': ['post(string,string,string,uint256,uint256,address)'], + '0xd5f37f95': ['sign(uint256,uint256,address)'], + '0xccbda1af': ['getChannelByName(string)'], + '0x738ddabe': ['getContentIndexedAccountCred(uint256,address,address)'], + '0x60dccd89': ['getContentAccount(uint256)'], + '0x05de4f07': ['getContentParent(uint256)'], + '0x9ea1b79d': ['getContentChannel(uint256)'], + '0xa5b9e922': ['getContentTimetamp(uint256)'], + '0x7e904a48': ['getNumContents(uint256)'], + '0xd644e356': ['index(uint256,address,uint256,uint256)'], + '0x0a4caed0': ['getChannelByRank(address,uint256)'], + '0x66099706': ['getChannelCred(address,uint256)'], + '0x5a1cc358': ['getChannelRank(address,uint256)'], + '0xffe34512': ['getNumChannels(address)'], + '0x771ad635': ['getContentCred(address,uint256)'], + '0x1d7e1f68': ['getContentRank(address,uint256)'], + '0xc01706dd': ['getContentByRank(address,uint256,uint256)'], + '0x2ae87a70': ['getNumContents(address,uint256)'], + '0x3b9901cc': ['getChannelsByRanks(address,uint256,uint256)'], + '0x9919b1cc': ['getContentsByRanks(address,uint256,uint256,uint256)'], + '0xf4dbeb9d': ['getCredRanksByContents(address,uint256[])'], + '0x6d1da953': ['createWithNonce(bytes32,bytes)'], + '0x67387d6b': ['testThrowCreateWithNonceExistingNonce()'], + '0x2aee19c7': ['testCreateWithNonce()'], + '0x81ebdeea': ['testThrowCreateWithNonceRetracted()'], + '0x089d5c4a': ['repr()'], + '0xaa237e21': ['set(bool,uint256)'], + '0xd1b1a22b': ['set(string,uint256[],uint256[],uint256[],bool[],uint256[])'], + '0x22bc3b8e': ['getArgument(uint256)'], + '0x0f3a1412': ['getArrlist(uint256,uint256)'], + '0xbb5d40eb': ['isValid()'], + '0x18921de4': [ + 'addSignature(string,uint256[],uint256[],uint256[],bool[],uint256[])' + ], + '0xd8c34127': ['isKnownSignature(string)'], + '0x6ba0b4f2': ['isKnownSelector(bytes4)'], + '0xa6cbcdd5': ['numSignatures(bytes4)'], + '0xe02426c1': ['getSignatureHash(bytes4,uint256)'], + '0x2324c67c': ['getAllSignatureHashes(bytes4)'], + '0xc4b14e0b': ['getSignature(bytes32)'], + '0x1baaeb91': ['getSignature(bytes4,uint256)'], + '0x0194db8e': ['sum(uint256[])'], + '0xcabb3a3a': ['isAlphaNumeric(string)'], + '0x7fdc8290': ['isUnderscore(bytes1)'], + '0x2973e372': ['isAlphaUpper(bytes1)'], + '0x9a571d9f': ['isAlphaLower(bytes1)'], + '0x342454c7': ['isDigit(bytes1)'], + '0xfadc51cf': ['isAlpha(bytes1)'], + '0xfd958695': ['isAlphaNumeric(bytes1)'], + '0xea3d508a': ['selector()'], + '0x4ed3885e': ['set(string)'], + '0x83d51a38': ['concatString(string)'], + '0x69d01268': ['concatUInt(uint256)'], + '0x364ea9e7': ['set(uint256,uint256,bool[],uint256[])'], + '0xcde0a4f8': ['setRegulator(address)'], + '0x483a83df': ['setKYC(address)'], + '0x5c7c9aa4': ['checkAccountState(address)'], + '0xbaccc92b': ['RegulatorIfc(address)'], + '0xbe3945e4': ['getFee(address,address,uint256)'], + '0x3395dc70': ['acceptTransfer(address,address,uint256)'], + '0x07b2779f': ['BasicRegulator(address,uint256,uint256)'], + '0x14cbdb54': ['EspCoin()'], + '0x1995333b': ['burnFunds(uint256)'], + '0x0ae5e739': ['grantAccess(address)'], + '0x85e68531': ['revokeAccess(address)'], + '0x95a078e8': ['hasAccess(address)'], + '0x56b8c724': ['transfer(address,uint256,string)'], + '0x1af716ba': ['transferFrom(address,address,uint256,string)'], + '0x24c93343': ['error(string)'], + '0x652f1f16': ['addSignature(string)'], + '0x560bb612': ['SignatureValidator(address)'], + '0x35b28153': ['addAuthorization(address)'], + '0x94f3f81d': ['removeAuthorization(address)'], + '0x7620a65b': ['Publisher()'], + '0xcc70bb1a': ['publish(string,string,string,address)'], + '0x8023ffbd': ['getOverallSize()'], + '0xebb741cb': ['getChannelSize(uint256)'], + '0xbbed7177': ['getContentTimestamp(uint256)'], + '0x8eaa1e29': ['getContentByData(address,uint256,string,string)'], + '0x69b144eb': ['testThrowsCreateNewRevisionNotOwner()'], + '0x334ef224': ['testThrowsUpdateLatestRevisionNotOwner()'], + '0xa6e16ba2': ['testThrowsRetractLatestRevisionNotOwner()'], + '0x6b6a53fa': ['testThrowsRestartNotOwner()'], + '0x869b3f6a': ['testThrowsRetractNotOwner()'], + '0xbc0e7adb': ['testThrowsDisownNotOwner()'], + '0xce19419b': ['testThrowsSetNotUpdatableNotOwner()'], + '0x67080f6e': ['testThrowsSetEnforceRevisionsNotOwner()'], + '0xe1569f6b': ['testThrowsSetNotRetractableNotOwner()'], + '0xb463bcde': ['testThrowsSetNotTransferableNotOwner()'], + '0x1da6822c': ['testThrowsTransferEnableNotTransferable()'], + '0x98024f18': ['testThrowsTransferDisableNotEnabled()'], + '0x06459119': ['testThrowsTransferNotTransferable()'], + '0xd3d6a975': ['testThrowsTransferNotEnabled()'], + '0xd4b1d19f': ['testThrowsTransferDisabled()'], + '0xd591221f': ['testTransfer()'], + '0x15a0df43': ['testThrowCreateNewRevisionNotOwner()'], + '0xe3a199d6': ['testThrowCreateNewRevisionNotUpdatable()'], + '0x42ce0f30': ['testThrowUpdateLatestRevisionNotOwner()'], + '0x835b42fc': ['testThrowUpdateLatestRevisionNotUpdatable()'], + '0x550bcd8d': ['testThrowUpdateLatestRevisionEnforceRevisions()'], + '0x46c3166f': ['testThrowRetractLatestRevisionNotOwner()'], + '0x2432eb23': ['testThrowRetractLatestRevisionNotUpdatable()'], + '0x531d1974': ['testThrowRetractLatestRevisionEnforceRevisions()'], + '0x6edb4cf6': [ + 'testThrowRetractLatestRevisionDoesntHaveAdditionalRevisions()' + ], + '0xfaf0952b': ['testThrowRestartNotOwner()'], + '0x85fe0448': ['testThrowRestartNotUpdatable()'], + '0xbb6a1427': ['testThrowRestartEnforceRevisions()'], + '0x23647398': ['testThrowRetractNotOwner()'], + '0x75a6a332': ['testThrowRetractNotRetractable()'], + '0x78205f67': ['testThrowTransferEnableNotTransferable()'], + '0xe5c7e509': ['testThrowTransferDisableNotEnabled()'], + '0x966acb38': ['testThrowTransferNotTransferable()'], + '0xd9ec0508': ['testThrowTransferNotEnabled()'], + '0x837a7ba5': ['testThrowTransferDisabled()'], + '0x7b48ba20': ['testThrowDisownNotOwner()'], + '0x938ae4cc': ['testThrowDisownNotTransferable()'], + '0x53caf582': ['testThrowSetNotUpdatableNotOwner()'], + '0xef41e06f': ['testThrowSetEnforceRevisionsNotOwner()'], + '0x20130753': ['testThrowSetNotRetractableNotOwner()'], + '0x5e1936d4': ['testThrowSetNotTransferableNotOwner()'], + '0x4123cb6b': ['m_numOwners()'], + '0x52375093': ['m_lastDay()'], + '0x659010e7': ['m_spentToday()'], + '0x746c9171': ['m_required()'], + '0x797af627': ['confirm(bytes32)'], + '0xb75c7dc6': ['revoke(bytes32)'], + '0xc2cf7326': ['hasConfirmed(bytes32,address)'], + '0xf1736d86': ['m_dailyLimit()'], + '0x96286cc9': ['isTokenOwner(address)'], + '0x69c8b344': ['ownedToken(address)'], + '0xe8580dd4': ['Survey(address,uint256,string,bytes32[])'], + '0x71c59097': ['MainnetSurvey(uint256,string,bytes32[])'], + '0x6e2edf30': ['ETCSurvey(address)'], + '0x58cb7323': ['MainnetETCSurvey()'], + '0x76d66f5d': ['_Transfer(address,address,bytes32)'], + '0x62c99e84': ['_Approval(address,address,bytes32)'], + '0x5fcc2edb': ['IndividualityTokenRoot(address)'], + '0xf3d91708': ['isEligibleForUpgrade(address)'], + '0x1a695230': ['transfer(address)'], + '0x103f9251': ['transferFrom(address,address)'], + '0x7dd56411': ['ownerOf(bytes32)'], + '0x7ca31724': ['tokenId(address)'], + '0xd55ec697': ['upgrade()'], + '0x216ef940': ['proxyUpgrade(address,address,bytes)'], + '0xc4128b6d': ['upgradeCount()'], + '0x09fc8f6d': ['isTokenUpgraded(bytes32)'], + '0x19a9c2f1': ['generateId(string)'], + '0xafb95eed': ['logApproval(address,address,bytes32)'], + '0x85d5c971': ['logTransfer(address,address,bytes32)'], + '0xbbba3333': ['safer_ecrecover(bytes32,uint8,bytes32,bytes32)'], + '0x77d32e94': ['ecrecovery(bytes32,bytes)'], + '0x39cdde32': ['ecverify(bytes32,bytes,address)'], + '0x72c3015c': ['mint(int256,address,string)'], + '0x6e0bd282': ['destroy(bytes32)'], + '0x983b2d56': ['addMinter(address)'], + '0x3092afd5': ['removeMinter(address)'], + '0x7d32e7bd': ['transfer(address,bytes32)'], + '0xb3c06f50': ['transferFrom(address,address,bytes32)'], + '0x5cd2f4d3': ['approve(address,bytes32)'], + '0x4fc9c91a': ['identityOf(bytes32)'], + '0x34b7ac9b': ['END_MINTING()'], + '0x899942b8': ['Devcon2Token()'], + '0x7993e5c2': ['Devcon2TokenForTesting()'], + '0x724121ae': ['contentExists(uint256)'], + '0x1003e2d2': ['add(uint256)'], + '0xa501e88d': ['Content()'], + '0x8570153e': ['publish(string,string,bytes,address[])'], + '0x76f30ca1': ['toContentID(address,uint256,string,bytes)'], + '0xee725d44': ['toChannelID(string)'], + '0x969cb7c3': ['getPublisher(uint256)'], + '0x110df916': ['getChannelID(uint256)'], + '0xb633620c': ['getTimestamp(uint256)'], + '0x4378a6e3': ['getAttributes(uint256)'], + '0x124eaee6': ['Identity()'], + '0xf207564e': ['register(uint256)'], + '0x4d207d9a': ['identify(address)'], + '0x54ea4000': ['identify(address[])'], + '0xeb782d8c': ['ContentSeries(address)'], + '0xde8fa431': ['getSize()'], + '0x21958a50': ['AddressSeries(address)'], + '0x504f1671': ['getSize(address)'], + '0xeb045789': ['ChannelSeries(address)'], + '0x023c23db': ['getSize(uint256)'], + '0x2fea7b81': ['getIdentity(address)'], + '0x043bb5e7': ['getIdentities(address[])'], + '0x27dc297e': ['__callback(bytes32,string)'], + '0x38bbfa50': ['__callback(bytes32,string,bytes)'], + '0xbc08afd9': ['WebOfTrustToken(address,uint256)'], + '0xa5bfa9a9': ['claimToken(bytes32)'], + '0x5669c94f': ['issueToken(address,string)'], + '0xcdcd77c0': ['baz(uint32,bool)'], + '0x0b811cb6': ['executeProposal(uint256,bytes32)'], + '0x1f5d0b4c': ['address(address,address,uint256)'], + '0x8ac0ca36': ['buyViaJohan()'], + '0xc1246d39': ['simulatePathwayFromBeneficiary()'], + '0x59e148fc': ['getLastOfferId()'], + '0x152583de': ['getAttributes()'], + '0x446d5aa4': ['getAttributes(address)'], + '0x88782386': ['UnicornMilk()'], + '0x13df7091': ['mintAll(int256)'], + '0xfa9acb05': ['addressInArray(address,address)'], + '0xb76e4890': ['Tester()'], + '0x0d2560ee': ['addMe()'], + '0x8894dd2b': ['addEther()'], + '0x1e9ea66a': ['balanceEther10000000(uint256)'], + '0xe5bf93b9': ['balanceEther(uint256)'], + '0xcd9f05b8': ['balanceEtherAddress(address)'], + '0xfd7ac203': ['TestToken()'], + '0x35b09a6e': ['someFunction()'], + '0x8f2c44a2': ['UnicornMilker()'], + '0xc26aa3c9': ['lockUnicorn(uint256)'], + '0xff556ecb': ['releaseUnicorn(uint256)'], + '0x27e8c2d8': ['burnUnicornShares()'], + '0xfff3c457': ['readMessages(uint256)'], + '0x6a226a49': ['addMessage(string)'], + '0x200ebe34': ['addTokensToGive(address)'], + '0x7a427d98': ['forceReturn()'], + '0xe53e04a5': ['refillGas()'], + '0x323082d7': ['Vote(string)'], + '0x90cf581c': ['voteYes()'], + '0x41c12a70': ['voteNo()'], + '0x49aa4ee2': ['removeVote()'], + '0xa48bdb7c': ['results()'], + '0x9832ee65': ['resultsWeightedByTokens()'], + '0x9dcb5c65': ['resultsWeightedByEther()'], + '0x49407a44': ['claimEther(uint256)'], + '0x509f8633': ['create_account()'], + '0x32fefb4c': ['add_account(address,address)'], + '0x9b5adea2': ['setMinter()'], + '0x0ecaea73': ['create(address,uint256)'], + '0xa24835d1': ['destroy(address,uint256)'], + '0x36f66528': ['EtherDelta(address,uint256,uint256)'], + '0x338b5dea': ['depositToken(address,uint256)'], + '0x9e281a98': ['withdrawToken(address,uint256)'], + '0xf7888aec': ['balanceOf(address,address)'], + '0x93f0bb51': [ + 'order(address,uint256,address,uint256,uint256,uint256,uint8,bytes32,bytes32)' + ], + '0x0a19b14a': [ + 'trade(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32,uint256)' + ], + '0x6c86888b': [ + 'testTrade(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32,uint256,address)' + ], + '0xfb6e155f': [ + 'availableVolume(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32)' + ], + '0xbb8be064': ['HardwareToken()'], + '0x57a373a1': ['uintInArray(uint256,uint256,int256,uint256[],uint256)'], + '0x32afa2f9': ['claimEtherOwner(uint256)'], + '0xa2a8336f': ['claimEtherSigner(uint256)'], + '0x4e077f2a': ['addGasEther()'], + '0x24804cef': ['Deed()'], + '0xfaab9d39': ['setRegistrar(address)'], + '0xfb1669ca': ['setBalance(uint256)'], + '0xbbe42771': ['closeDeed(uint256)'], + '0x0b5ab3d5': ['destroyDeed()'], + '0xa06cab79': ['Registrar(address,bytes32)'], + '0x367bbd78': ['strlen(string)'], + '0x03985426': ['getMode(bytes32)'], + '0xede8acdb': ['startAuction(bytes32)'], + '0xe27fe50f': ['startAuctions(bytes32[])'], + '0x22ec1244': ['shaBid(bytes32,address,uint256,bytes32)'], + '0xce92dced': ['newBid(bytes32)'], + '0xaefc8c72': ['unsealBid(bytes32,address,uint256,bytes32)'], + '0xdf7cec28': ['cancelBid(bytes32)'], + '0x983b94fb': ['finalizeAuction(bytes32)'], + '0x0230a07c': ['releaseDeed(bytes32)'], + '0x15f73331': ['invalidateName(string)'], + '0x5ddae283': ['transferRegistrars(bytes32)'], + '0xebb045fa': ['PublicResolver(address)'], + '0x41b9dc2b': ['has(bytes32,bytes32)'], + '0x01ffc9a7': ['supportsInterface(bytes4)'], + '0x3b3b57de': ['addr(bytes32)'], + '0xd5fa2b00': ['setAddr(bytes32,address)'], + '0x2dff6941': ['content(bytes32)'], + '0xc3d014d6': ['setContent(bytes32,bytes32)'], + '0x1d2e2cc4': ['ENS()'], + '0x02571be3': ['owner(bytes32)'], + '0x0178b8bf': ['resolver(bytes32)'], + '0x16a25cbd': ['ttl(bytes32)'], + '0x5b0fc9c3': ['setOwner(bytes32,address)'], + '0x06ab5923': ['setSubnodeOwner(bytes32,bytes32,address)'], + '0x1896f70a': ['setResolver(bytes32,address)'], + '0x14ab9038': ['setTTL(bytes32,uint64)'], + '0x9d063ed8': ['FIFSRegistrar(address,bytes32)'], + '0xd22057a9': ['register(bytes32,address)'], + '0xe8efc1a0': ['updatedValue(bytes32)'], + '0x3dfb4843': ['renewDeed(bytes32)'], + '0xd8389dc5': ['hash(bytes32)'], + '0xd7fa1007': ['setHash(bytes32,bytes32)'], + '0x003538c5': ['TestRegistrar(address,bytes32)'], + '0x267b6922': ['entries(bytes32)'], + '0x3f15457f': ['ens()'], + '0x61584936': ['sealedBids(bytes32)'], + '0xb88eef53': ['registryCreated()'], + '0xfaff50a8': ['rootNode()'], + '0x8b859409': ['setRelease(bytes32,bytes32,string)'], + '0x244fcd03': ['removeRelease(bytes32,string)'], + '0x89859b50': ['updateLatestTree(bytes32)'], + '0xa10889fa': ['setVersion(uint32,uint32,uint32,string,string)'], + '0x0ccec396': ['getNumReleases()'], + '0x57b07cd9': ['getReleaseHash(uint256)'], + '0x173cb7de': ['getNumReleasesForNameHash(bytes32)'], + '0x0c26e42e': ['getReleaseHashForNameHash(bytes32,uint256)'], + '0x3f415772': ['releaseExists(bytes32)'], + '0xbb814e9e': ['versionExists(bytes32)'], + '0x4c4aea87': ['getReleaseData(bytes32)'], + '0x0c4326a0': ['getMajorMinorPatch(bytes32)'], + '0xfac5bb92': ['getPreRelease(bytes32)'], + '0x8ca4eef6': ['getBuild(bytes32)'], + '0x2ffb8631': ['getReleaseLockfileURI(bytes32)'], + '0x0e5ffb3c': ['hashVersion(uint32,uint32,uint32,string,string)'], + '0x93d79105': ['hashRelease(bytes32,bytes32)'], + '0x3ae9b510': ['getLatestMajorTree(bytes32)'], + '0xf2f254c7': ['getLatestMinorTree(bytes32,uint32)'], + '0x5263ba87': ['getLatestPatchTree(bytes32,uint32,uint32)'], + '0xdea9c72b': ['getLatestPreReleaseTree(bytes32,uint32,uint32,uint32)'], + '0xd7cc8362': ['isLatestMajorTree(bytes32,bytes32)'], + '0xd1f59db9': ['isLatestMinorTree(bytes32,bytes32)'], + '0xc233e870': ['isLatestPatchTree(bytes32,bytes32)'], + '0x02de2cf3': ['isLatestPreReleaseTree(bytes32,bytes32)'], + '0x02556de3': ['updateMajorTree(bytes32)'], + '0x44d75fa9': ['updateMinorTree(bytes32)'], + '0xb6ac24df': ['updatePatchTree(bytes32)'], + '0x900d85fa': ['updatePreReleaseTree(bytes32)'], + '0xbed34bba': ['compareStrings(string,string)'], + '0x15398afe': ['compareNumericStrings(string,string)'], + '0xdd79e33e': ['splitIdentifiers(string)'], + '0x2fc0aad3': ['isNumericString(string)'], + '0x55ff440a': ['castStringToUInt(string)'], + '0xb7009613': ['canCall(address,address,bytes4)'], + '0xeacfc0ae': ['Authorized()'], + '0x87045369': ['setCanCall(address,address,bytes4,bool)'], + '0x02acdb44': ['setAnyoneCanCall(address,bytes4,bool)'], + '0x20d9822e': ['setAnyoneCanCall(address,string,bool)'], + '0x083ae1fe': ['setPackage(string)'], + '0x001f8d11': ['removePackage(bytes32,string)'], + '0x2406cedb': ['setPackageOwner(bytes32,address)'], + '0xa9b35240': ['packageExists(bytes32)'], + '0x7370a38d': ['getNumPackages()'], + '0x95f0684b': ['getPackageNameHash(uint256)'], + '0xb4d6d4c7': ['getPackageData(bytes32)'], + '0x06fe1fd7': ['getPackageName(bytes32)'], + '0xaf9a3f9b': ['hashName(string)'], + '0x34c0d654': ['setPackageDb(address)'], + '0xf314bf46': ['setReleaseDb(address)'], + '0x10ae4ce2': ['setReleaseValidator(address)'], + '0x5fcb568c': ['release(string,uint32,uint32,uint32,string,string,string)'], + '0x0f3d7c3e': ['release(string,uint32[3],string,string,string)'], + '0x4f197ee7': ['transferPackageOwner(string,address)'], + '0x83ea0620': ['packageExists(string)'], + '0x4188d79c': ['releaseExists(string,uint32,uint32,uint32,string,string)'], + '0xcfe9a7b8': ['getPackageName(uint256)'], + '0xc2ba5b40': ['getPackageData(string)'], + '0xcec95aa1': ['getReleaseHashForPackage(string,uint256)'], + '0xc392f5a0': ['getAllPackageReleaseHashes(string)'], + '0x12cc08f2': ['getPackageReleaseHashes(string,uint256,uint256)'], + '0x4cb71b9b': ['getAllReleaseHashes()'], + '0x79cce1c5': ['getReleaseHashes(uint256,uint256)'], + '0x1f6b0a9d': [ + 'getReleaseLockfileURI(string,uint32,uint32,uint32,string,string)' + ], + '0x79c3ddc1': ['isPackageOwner(string,address,address)'], + '0x91060168': ['fetchString(address,bytes4,bytes32)'], + '0xfa28ba0d': ['validateReleaseLockfileURI(string)'], + '0xf4ea95b9': ['validateReleaseVersion(uint32[3])'], + '0x6f0cfab6': ['DNSResolver()'], + '0x126a710e': ['dnsrr(bytes32)'], + '0x76196c88': ['setDnsrr(bytes32,bytes)'], + '0x61d585da': ['state(bytes32)'], + '0xe571c35e': ['ReverseRegistrar(address,bytes32)'], + '0x1e83409a': ['claim(address)'], + '0xbffbe61c': ['node(address)'], + '0x27b752b8': ['sha3HexAddress(address)'], + '0xe1fa8e84': ['register(bytes32)'], + '0xa31d5580': ['Registrar(address,bytes32,address)'], + '0x3ea3f6c5': ['activateRegistrar()'], + '0x271cd760': ['getPackageDb()'], + '0xfb3a1fb2': ['getReleaseDb()'], + '0x4961b40c': ['getReleaseValidator()'], + '0x2d34ba79': ['setup(address,address)'], + '0x30b9af98': ['withdrawFunding()'], + '0x92a781d8': ['changeBaseValue(uint256)'], + '0xb60d4288': ['fund()'], + '0xc062f578': ['updateStage()'], + '0xf3a44fe1': ['withdrawForWorkshop()'], + '0x99e0021f': ['mergencyCall()'], + '0x299ed37a': ['emergencyCall()'], + '0x0b7abf77': ['TOTAL_TOKENS()'], + '0x17f5de95': ['MAX_TOKENS_SOLD()'], + '0x39f64b52': ['calcTokenPrice()'], + '0x48c54b9d': ['claimTokens()'], + '0x48cd4cb1': ['startBlock()'], + '0x521eb273': ['wallet()'], + '0x60fd902c': ['gnosisToken()'], + '0x62ea82db': ['bids(address)'], + '0x6f85c7e4': ['WAITING_PERIOD()'], + '0x8da5cb5b': ['owner()'], + '0xa3c2c462': ['totalReceived()'], + '0xa6b513ee': ['finalPrice()'], + '0xc040e6b8': ['stage()'], + '0xc51bf934': ['CEILING()'], + '0xd9f8a4e2': ['calcCurrentTokenPrice()'], + '0xdd9dd688': ['calcStopPrice()'], + '0xde78e78a': ['tokenLaunched()'], + '0x4c6b25b1': ['results(bytes32)'], + '0x69347990': ['ownerWithdrawl()'], + '0x7b1aa45f': ['ownerDeposit()'], + '0x996a8046': ['__callback(bytes32,string,bool)'], + '0xb964608d': ['get_return_by_level(uint256)'], + '0xcddbe729': ['game(uint256)'], + '0x0674763c': ['assert(bool)'], + '0xe21608be': ['ReserveToken()'], + '0x1cbd0519': ['accountLevel(address)'], + '0x8abadb6b': ['setAccountLevel(address,uint256)'], + '0x4c7f74df': ['EtherDelta(address,address,address,uint256,uint256,uint256)'], + '0x8f283970': ['changeAdmin(address)'], + '0xe8f6bc2e': ['changeAccountLevelsAddr(address)'], + '0x71ffcb16': ['changeFeeAccount(address)'], + '0x54d03b5c': ['changeFeeMake(uint256)'], + '0x8823a9c0': ['changeFeeTake(uint256)'], + '0x5e1d7ae4': ['changeFeeRebate(uint256)'], + '0x0b927666': ['order(address,uint256,address,uint256,uint256,uint256)'], + '0x05888fcd': [ + 'tradeBalances(address,uint256,address,uint256,address,uint256)' + ], + '0x46be96c3': [ + 'amountFilled(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32)' + ], + '0x278b8c0e': [ + 'cancelOrder(address,uint256,address,uint256,uint256,uint256,uint8,bytes32,bytes32)' + ], + '0x60116397': ['Registrar(address,bytes32,uint256)'], + '0xf4dc2d21': ['Deed(uint256)'], + '0x06fdde03': ['name()'], + '0x313ce567': ['decimals()'], + '0x40275f85': ['getPersonalDepositAddress(address)'], + '0x5a3b7e42': ['standard()'], + '0x89d59ee5': ['createPersonalDepositAddress()'], + '0x8c546f81': ['GNT()'], + '0x8f70bfa0': ['processDeposit()'], + '0x95d89b41': ['symbol()'], + '0xb414d4b6': ['frozenAccount(address)'], + '0xdc3080f2': ['spentAllowance(address,address)'], + '0x366a68dc': ['setBlockLock(uint256)'], + '0xa39a45b7': ['replaceOwner(address)'], + '0xa4e2d634': ['isLocked()'], + '0xd8162db7': ['lockedUntilBlock()'], + '0x1593a8c7': ['endLottery()'], + '0x53aab434': ['buyIn()'], + '0x5ec01e4d': ['random()'], + '0x6939864b': ['lotteryState()'], + '0xd366fbab': ['startLottery(bytes32,uint256,uint256,uint256,uint256,bool)'], + '0xfd7c460d': ['ciberLottery()'], + '0x2525f5c1': ['cancelBid(address,bytes32)'], + '0xc01a8c84': ['confirmTransaction(uint256)'], + '0x1209b1f6': ['ticketPrice()'], + '0x50b44712': ['tickets(uint256)'], + '0x5c3f9765': ['endDateClose()'], + '0x984ac378': ['lotteryTitle()'], + '0xb8851fea': ['endDateStart()'], + '0xc179520c': ['ManageAccount()'], + '0x12494160': ['isHolder()'], + '0x42ce1488': ['upload(string)'], + '0x3c925f16': ['getAccountHolder()'], + '0x83f7b8e1': ['getNumberOfPhotos()'], + '0xe2a71f12': ['accountDelete()'], + '0x009b9369': ['getVoteNumber(uint256)'], + '0x0ee79fb3': ['closeReferendums()'], + '0x291e6777': ['sendVote(uint256,uint256)'], + '0x32d2fb9f': ['getRefRemainingTime(uint256)'], + '0x3b0506f7': ['getVoteByAddress(address,uint256)'], + '0x62fb09b2': ['getRefDescr(uint256)'], + '0x77a7e6be': ['getRefTotal(uint256)'], + '0x80dcaf27': ['getRefNumber()'], + '0x8736fd16': ['getRefStatus(uint256)'], + '0xace523c4': ['createReferendum(string,string,uint256,uint256)'], + '0xb29d7914': ['getRefResults(uint256)'], + '0xc0df77d0': ['getRefName(uint256)'], + '0x94d9cf8f': [ + 'CreateProxyWithControllerAndRecovery(address,address[],uint256,uint256)' + ], + '0x4a3a87e2': [ + 'CreateProxyWithControllerAndRecoveryKey(address,address,uint256,uint256)' + ], + '0x4fcf8210': ['eraseRecord(bytes32)'], + '0xde10f04b': ['eraseNode(bytes32[])'], + '0x3a76abff': ['_eraseNode(uint256,bytes32[],bytes32)'], + '0x1cda37f2': ['eraseRecords(bytes32)'], + '0x00e43ee9': ['setMigrationStatus(uint256,address)'], + '0x984413b8': ['_eraseNode(bytes32)'], + '0xb0c80972': ['setBalance(uint256,bool)'], + '0xfebefd61': ['startAuctionsAndBid(bytes32[],bytes32)'], + '0x77bc222c': ['_eraseSingleNode(bytes32)'], + '0x57aee888': ['_eraseNodeHierarchy(uint256,bytes32[],bytes32)'], + '0xdce293a7': ['minLength(uint256)'], + '0xaf92a693': ['addRegistrar(address)'], + '0xba904eed': ['removeRegistrar(address)'], + '0x081780f4': ['clearRecord(bytes32)'], + '0xb0349184': ['clearRecords(bytes32[])'], + '0xf62cce34': ['_clearRecordHierarchy(uint256,bytes32[],bytes32)'], + '0x36b81feb': ['Deed(address)'], + '0x4a617faa': ['shaBid(bytes32,uint256,bytes32)'], + '0x47872b42': ['unsealBid(bytes32,uint256,bytes32)'], + '0x93503337': ['isAllowed(bytes32,uint256)'], + '0x8a4068dd': ['transfer()'], + '0x13c89a8f': ['getAllowedTime(bytes32)'], + '0xa360b26f': ['Migrations()'], + '0xfdacd576': ['setCompleted(uint256)'], + '0x99a88ec4': ['upgrade(address,address)'], + '0x8e7fd292': ['trySetSubnodeOwner(bytes32,address)'], + '0x29cd5777': ['_tryEraseSingleNode(bytes32)'], + '0x5e431709': ['sealedBids(address,bytes32)'], + '0x9c67f06f': ['registryStarted()'], + '0xea9e107a': ['acceptRegistrarTransfer(bytes32,address,uint256)'], + '0x05b34410': ['creationDate()'], + '0x2b20e397': ['registrar()'], + '0x3fa4f245': ['value()'], + '0x674f220f': ['previousOwner()'], + '0x2203ab56': ['ABI(bytes32,uint256)'], + '0x623195b0': ['setABI(bytes32,uint256,bytes)'], + '0xc8690233': ['pubkey(bytes32)'], + '0x29cd62ea': ['setPubkey(bytes32,bytes32,bytes32)'], + '0x691f3431': ['name(bytes32)'], + '0x77372213': ['setName(bytes32,string)'], + '0x20d8741f': ['Feed()'], + '0xdd114c22': ['publish(address,uint256,address,uint256)'], + '0xfb279ef3': ['tip(uint256,address,uint256)'], + '0x96c824a8': ['createAccountFundContract()'], + '0x33397816': ['withdrawAccountBalance(address)'], + '0x6ebbe863': ['updatePublishContract(address)'], + '0xfad4b99a': ['updateChannelMinimum(address,uint256)'], + '0x0b7ad54c': ['getContent(uint256)'], + '0xda9c6a46': ['getReplyCount(uint256)'], + '0x47372325': ['getChannelSize(address)'], + '0x2ca6d2c0': ['getAccountSize(address)'], + '0x73f93a48': ['getAccountContentTip(address,uint256)'], + '0x0a7f4239': ['getAccountFundContract(address)'], + '0x0fcda174': ['getAccountTokenBalance(address,address)'], + '0x79be02af': ['Read(address)'], + '0x27fbcac5': ['getChannelFeed(address,uint256,uint256)'], + '0xdd90c403': ['getAccountFeed(address,uint256,uint256)'], + '0xbff974e8': ['getContentReplies(uint256)'], + '0xb3822da8': ['getContents(uint256[])'], + '0x2a45a39a': ['Post(address)'], + '0xe3579ea5': ['publish(string,string,address,uint256)'], + '0x4c8cc20b': ['toContentID(address,string,string,address,uint256)'], + '0x6ce1417e': ['Fund()'], + '0xea46193e': ['getEtherBalance()'], + '0x55291dbd': ['claimEther()'], + '0xe9e99d81': ['getChannelFeed(address,uint256,uint256,uint256)'], + '0x05a17fc6': ['getAccountFeed(address,uint256,uint256,uint256)'], + '0xd90a88cd': ['getContentReplies(uint256,uint256)'], + '0x49e347ae': ['getContents(uint256[],uint256)'], + '0xbac1e9f6': ['getChannelSize(address,uint256)'], + '0x048e2e94': ['getAccountSize(address,uint256)'], + '0x9f181b5e': ['tokenCount()'], + '0xf446c1d0': ['A()'], + '0x314e99a2': ['abdicate()'], + '0x9b0b9c07': ['acceptBankDraft()'], + '0xbdfdb519': ['accept(string,uint256,uint16)'], + '0x8f5e9ca7': ['acceptTOS(address,bool)'], + '0xa79deb4f': ['acceptTradeDeal()'], + '0x5a28340a': ['accessOperatingBudget(uint256)'], + '0xa8b60b93': ['ackMsg(uint256,string)'], + '0x7ec0f30d': ['ack(string)'], + '0x82a62137': ['activateAccount(address)'], + '0x1e9fcc77': ['activateAllowance(address,address)'], + '0x6bd92f7c': ['activateAllowanceRecord(address,address)'], + '0x0651844e': ['activateBalance(address)'], + '0xc8e49707': ['activateExportFee(address)'], + '0x2cd78450': ['activateExportFeeChargeRecord(address)'], + '0xd532e481': ['activateFrozenAccount(address)'], + '0x1d2b7155': ['activateImportFeeChargeRecord(address)'], + '0xcf03f5f4': ['activateMasterKey(address)'], + '0x1917ab5c': ['activate(string)'], + '0x0b2acb3f': ['add(address,bytes)'], + '0xec97cff7': ['addCertificationDocument(address,bytes32)'], + '0xa0d605c6': ['addCertificationDocumentInternal(address,bytes32)'], + '0xe80bd3e5': ['addCertificationDocumentToSelf(bytes32)'], + '0x2b198366': ['addCertifier(address)'], + '0xac3e7d24': ['addChainyData(string)'], + '0x9450b1c8': ['addCharityFundation(string,string,string)'], + '0x6ac6205c': ['addDataPoint(int256,uint256,bool,string)'], + '0x4094ef5e': ['addDataRequest(string)'], + '0xd3118a5a': ['addDoc(string,string)'], + '0x20339891': ['addGridMember(address)'], + '0x61bffe01': ['addIdentities(bytes32[],bytes32[])'], + '0x17b3a34b': ['_addIdentities(uint256,bytes32[])'], + '0x17e1bfb7': ['addInstitution(address,string)'], + '0xf824384a': ['addInvestorAtID(uint256)'], + '0x202d6eaf': ['addInvestorsValue(uint256)'], + '0x2fe9541f': ['addIssueBounty(string,uint256)'], + '0x2d06177a': ['addManager(address)'], + '0x2ba0b09f': ['AddNewCategory(bytes4,uint8,uint8,address)'], + '0x29dfdded': ['addNewDonkey(address)'], + '0x74bfb965': ['addNewProxy(address)'], + '0x755f99c2': ['AddNewSmallContract(address)'], + '0xc1d5e84f': ['addNewUser(address)'], + '0x76849376': ['addNode(bytes32,address)'], + '0x7d380265': [ + 'addOptionChain(uint256,string,uint256,uint256,bytes32,address,int256[])' + ], + '0x227f9633': ['addOption(string,address,uint256)'], + '0xdf5dd1a5': ['addOracle(address)'], + '0x3c0dde1c': ['_addPools(address,address)'], + '0x3d90d44d': ['addPowerSource(address,uint256,uint256)'], + '0x49bf66d3': ['addRegistryIntoNameIndex(address)'], + '0xb796a339': ['addRegistryIntoOwnerIndex(address,address)'], + '0x7cdbae63': ['addRegistryIntoTagsIndex(address)'], + '0x3e82055a': ['addSignature(uint256,bytes16,bytes)'], + '0xd1feca67': ['addSpendingRequest(address)'], + '0xdab80d6f': ['addSponsor(address)'], + '0xb0c8f9dc': ['add(string)'], + '0x8396392d': ['add(string,string,string,address)'], + '0x36555b85': ['add(string,uint256)'], + '0xd2dc0869': ['add(string,uint256,string,string,address)'], + '0x0f3eb785': ['add(string,uint256,uint256,uint256)'], + '0x38178fbe': ['addString(string,string)'], + '0x45590ec8': ['addTag(uint256,string)'], + '0x0e1d88fc': ['addTender(uint256,uint256,address,uint256)'], + '0x7f0899f2': ['AddTicket(bytes5[])'], + '0xd48bfca7': ['addToken(address)'], + '0x75c4aaa6': ['addUnderDog(uint256)'], + '0x213ac932': ['addUser(address,uint256,uint8,bytes32,bytes32)'], + '0x9da680f3': ['adjustRegistrationFee(uint256)'], + '0x5b6a54bc': ['adjustTransactionFee(uint256)'], + '0x40fdef80': ['administration(uint256,string,uint256,uint256,address)'], + '0xbc21ce9d': ['Aggregation()'], + '0x98688a95': ['Ai()'], + '0xbd3f0965': ['AiraEtherFunds(string,string)'], + '0xe1efda6d': ['airaSend(address,address,uint256)'], + '0x6d2cb794': ['airaTransfer(address,address,uint256)'], + '0xa9f8ec6c': ['AlarmClockTipFaucet()'], + '0x4a8b5389': ['allocateBountyAndEcosystemTokens()'], + '0xbcfcb03e': ['allocateFounderTokens()'], + '0xd526b9bd': ['_allow()'], + '0x1c8d5d38': ['allowance(address,address,bytes32)'], + '0xeb06e65e': ['allowanceFromProxy(address,address,address)'], + '0x9c0a4bbc': ['AlwaysFail()'], + '0x3b591ea7': ['AmountToForgeTheNextBlock()'], + '0x6056969b': ['announce(bytes32)'], + '0x3ef8ec78': ['announce_numbers(uint8,uint8,uint8,uint8,uint32,bytes32)'], + '0xea0a5237': ['announce(string)'], + '0xac04f5a7': ['append(address)'], + '0x94ed9b77': ['append(address,address)'], + '0x9aaf442c': ['applyCensorship(uint256)'], + '0x691d58e7': ['_applyRefund(uint256)'], + '0x7b7d7225': ['_approve(address,uint256)'], + '0x6d1669e1': ['approveAndCall(address,address,uint256,bytes)'], + '0xf11c4482': ['approveFromProxy(address,address,uint256)'], + '0x7df52ba8': ['Arbitrate(uint32,uint32,bool)'], + '0x99154b49': ['ARK()'], + '0x014e5fde': ['ARKController_1_00()'], + '0xfb32f4f5': ['ARK_FLAGGER_1_00()'], + '0x2be6d43c': ['ARKTagger_1_00()'], + '0xae30d35d': ['ARK_TROGLOg_1_00()'], + '0x97709cde': [ + 'ARK_VOTER_1_00(uint256,uint256,uint256,uint256,uint256,uint256)' + ], + '0xdba21657': ['askForEther(uint256)'], + '0x8a3e44d4': ['assetMoveInformation(address,address)'], + '0x0399c357': ['assignFreeReadings(address,uint8)'], + '0x7fe0518a': ['asyncSend(address,uint256)'], + '0xa843c97f': ['attack(uint256,uint256,uint256[])'], + '0xe0886f90': ['at(uint256)'], + '0x373c98a2': ['authCall(address,bytes32)'], + '0x39b35753': ['authCancel(address)'], + '0x4a5db3b5': ['authorizeAddress(address)'], + '0x2db89533': ['Auth(uint8,address)'], + '0x10cf5d47': ['awaitingPayout()'], + '0x3d79d1c8': ['bal()'], + '0x0a6be0e7': ['BalancedPonzi()'], + '0x4d30b6be': ['balanceOf(address,bytes32)'], + '0x61a00f6d': ['Ballot(bytes32[])'], + '0x940f851c': ['Ballot(uint8)'], + '0x97c3ccd8': ['ban(address)'], + '0xb5deeca7': ['BaseRegistry()'], + '0xcbe9ef39': ['BasicCoin(uint256,address)'], + '0xd767aee0': ['bbb()'], + '0x738486bd': ['BeerCoin(uint256)'], + '0xf79b22e0': ['betOnATeam(uint256)'], + '0xd30a512e': ['betOnColumnOrDozen(bool,bool,bool)'], + '0x86314af9': ['BetOnHashV84()'], + '0x3adb2de7': ['bet_this_spin()'], + '0x416c8701': ['beyond()'], + '0x934db458': ['Big()'], + '0x71dd99fe': ['BigRisk()'], + '0xf67a1d37': ['BlockChainChallenge()'], + '0x8a519fb9': ['BlockChainEnterprise()'], + '0x9ad4f98e': ['BlocksureInfo()'], + '0x48d9a374': ['blockTransfer(address,uint256)'], + '0x00601d6c': ['board(uint256,uint8,uint8)'], + '0xd1100691': ['BookCafe()'], + '0xbb00fc55': ['bookEarnings()'], + '0x9eee85fe': ['bookEarnings(address,uint256)'], + '0xdba7ef7d': ['Bookie(address,address)'], + '0x60913244': ['botOnSale(uint256,uint256)'], + '0x4cb85356': ['BranchSender(uint256,bytes32)'], + '0x0ad95b44': ['bribery()'], + '0xb0ad38c4': ['buildCity(string,uint256[2],uint256[2])'], + '0xdad99989': ['burnCoins(address)'], + '0x5fc5d48b': ['burnUnsoldCoins(address)'], + '0x3824d8ee': ['buy100DaoFor1Eth()'], + '0x561a4873': ['buyAd(string,string,string,uint256,uint8,address)'], + '0x5f8f0483': ['buyBankerAgreementFromImporterBank()'], + '0x29274fe1': ['buyBOTx(uint256,string,string,address,uint256)'], + '0xe75528cc': ['buyBuilding(uint256,uint256)'], + '0xe7e2aa0e': ['buyer_cancel()'], + '0xd04bfc9c': ['buyer_pay()'], + '0x29cbdc86': ['buyin(address,uint256)'], + '0x4ea66c38': ['buyinInternal(address,uint256)'], + '0xd24ddcfe': ['buyKissBTC()'], + '0x854f4817': ['buyKissBTCWithCallback(address,uint256)'], + '0xdda44b10': ['buyRecipient(address,uint8,bytes32,bytes32)'], + '0xcef8d343': ['buyShare(uint256,bool)'], + '0x90cb04e1': ['buy(string,uint256,uint16)'], + '0xedca914c': ['buyTicket()'], + '0x920c94df': ['BuyTicketForOther(address,uint8,uint8,uint8)'], + '0x378c0605': ['buyTickets(address)'], + '0x46f7a883': ['BuyTicket(uint8,uint8,uint8)'], + '0xaaf9d13e': ['buyTopDog(uint256,uint256)'], + '0xe5fe4f31': ['buy(uint8,bytes32,bytes32)'], + '0x4b8772c1': ['buyUnit(uint256,uint256)'], + '0xb412d4d6': ['CafeDelivered()'], + '0x4dda1764': ['CafeMaker()'], + '0x4dc3141b': ['CalcAll()'], + '0xea295ec2': ['calcRevenue(address)'], + '0xc1cc0775': ['calculateFeeDynamic(uint256,uint256)'], + '0xc03e382f': ['calculateShare()'], + '0x671dacdc': ['CalculateSqrt(uint256)'], + '0xdcf8113e': ['campaignEndedSuccessfully()'], + '0x74e60a48': [ + 'cancelOrder(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32)' + ], + '0xdc419fd8': ['cancelOrder(bool,uint256)'], + '0x3fb0b2c9': ['CancelRoundAndRefundAll()'], + '0x9d1bbd7e': ['CancelRoundAndRefundAll(uint256)'], + '0x6618b008': ['cancelSellOrder(address)'], + '0x39b50688': ['cancelSellOrder()'], + '0x06909f69': ['cancel(string,uint256)'], + '0x1d3390a1': ['carefulSendWithFixedGas(address,uint256,uint256)'], + '0x5cff876b': ['carrotsCaught()'], + '0x4bb4b260': ['cashAllOut()'], + '0xe2861c8d': ['cashOutProfit()'], + '0x4a30f976': ['censorship(uint256,bool,bool)'], + '0x05b2b03a': ['CertificationCentre(address)'], + '0x35d79fad': ['CertificationDb(address,uint256,address)'], + '0xf72457af': ['CertifierDb()'], + '0x5103a5a3': ['certify(address,bytes32)'], + '0x0f096163': ['Chainy()'], + '0xdabdc1f2': ['ChangeActiveDigger(address)'], + '0x839849c0': ['changeBaseMultiplier(uint256)'], + '0x1ed6f423': ['changeDescription(address,string)'], + '0x75090ebf': ['changeDomain(uint256,uint256,uint256,address)'], + '0x3fd94686': ['changeEligibleDonkeys(uint256)'], + '0x6a1db1bf': ['changeFee(uint256)'], + '0x93c32e06': ['changeFounder(address)'], + '0xd21d7950': ['changeGasLimitOfSafeSend(uint256)'], + '0x62ee6d29': ['changeHashtoLowOrHigh(uint256)'], + '0x1efb17ee': ['changeHouseAddress(address)'], + '0xeb1ff845': ['changeId(uint256,uint256,uint256)'], + '0x07a9574a': ['changeLeaderMessage(string)'], + '0x53fefd7d': ['changeMaxDeposit(uint256)'], + '0xa51aea2d': ['changeMaxMultiplier(uint256)'], + '0x45ca25ed': ['changeName(address,string)'], + '0x85eac05f': ['changeOwnerAddress(address)'], + '0x244ded7a': ['ChangeOwnership(address)'], + '0xc0b92612': ['changePig(address)'], + '0x0fffbb54': ['changeRankingSize(uint256)'], + '0x1982ed58': ['ChangeReuseCashInHarware(bool,uint16,uint16)'], + '0xcdcb7c8f': ['chase()'], + '0x919840ad': ['check()'], + '0xc23697a8': ['check(address)'], + '0xede8ebf3': ['checkApprove(address,uint256)'], + '0x20e647e1': ['checkBetColor(uint8,address,bytes32,bytes32)'], + '0xf2b904c3': ['checkBetColumn(uint8,address,bytes32,bytes32)'], + '0x74388347': ['checkBetDozen(uint8,address,bytes32,bytes32)'], + '0x75830463': ['checkBetLowhigh(uint8,address,bytes32,bytes32)'], + '0x40c0bcb9': ['checkBetNumber(uint8,address,bytes32,bytes32)'], + '0xe9c31315': ['checkBetParity(uint8,address,bytes32,bytes32)'], + '0x1e5330ca': ['checkBetResult(uint8,address,bytes32,bytes32)'], + '0x90a85119': ['checkBetResult(uint8)'], + '0xc67146a5': ['check_bet(uint256,address,uint8)'], + '0xf062e26b': ['check_darkdao()'], + '0x1a9360dd': ['checkDate()'], + '0x32921690': ['checkDepth(address,uint256)'], + '0xdc3ab866': ['checkEarnings(address)'], + '0x51fdaf92': ['checkExpiredfunds()'], + '0x46b207b8': ['checkExpiry()'], + '0xe95bee59': ['checkFormat(string)'], + '0x119aa5c8': ['checkForward(bytes)'], + '0x19483cd1': ['checkHash()'], + '0x0382c254': ['CheckHash(uint8,uint8,uint8,uint8,bytes32)'], + '0x255016c8': ['checkIfExploded()'], + '0x0343dfa0': ['checkInvariants()'], + '0x4c7a2254': ['checkMyWithdraw()'], + '0x33893071': ['checkMyWithdraw(address)'], + '0xb2bfd948': ['checkNumbers(uint8[3])'], + '0xbed411a0': ['CheckPrize(address)'], + '0xb623f5e5': ['checkSetCosignerAddress(address)'], + '0xef19c332': ['_checkSigned(bytes32,uint256,uint8,bytes32,bytes32)'], + '0x3c959aca': ['CheckTickets()'], + '0xe0c6190d': ['checkTime()'], + '0x5329c681': ['checkTimeout(uint256)'], + '0x88e072b2': ['checkTransfer(address,uint256)'], + '0xc5575ef0': ['checkTransferFrom(address,address,uint256)'], + '0x00a7d6b3': ['checkTransferFromToICAP(address,bytes32,uint256)'], + '0xbd8c1d33': [ + 'checkTransferFromToICAPWithReference(address,bytes32,uint256,string)' + ], + '0xc6e0c908': [ + 'checkTransferFromWithReference(address,address,uint256,string)' + ], + '0x8e4afa51': ['checkTransferToICAP(bytes32,uint256)'], + '0x058026d0': ['checkTransferToICAPWithReference(bytes32,uint256,string)'], + '0xcbcaacab': ['checkTransferWithReference(address,uint256,string)'], + '0x5f72f450': ['check(uint256)'], + '0x22d8cf5b': ['CheckUserVote(uint8,uint8)'], + '0xefdecd9b': ['check_withdrawdao()'], + '0xbd66528a': ['claim(bytes32)'], + '0x008a745d': ['claimDividendShare(uint256)'], + '0x0b3ed536': ['claimDonations(uint256)'], + '0xb88a802f': ['claimReward()'], + '0x3b751f7f': ['claimThroneRP(string)'], + '0xe6e7237f': ['claim_time_victory(uint256)'], + '0x4a1aa767': ['claim_victory(uint256,uint8,uint8,uint8)'], + '0x4e05ded6': ['ClassicCheck()'], + '0x565a2ecf': ['classicTransfer(address)'], + '0x2526d960': ['clawback()'], + '0x01775f23': ['_closeBooks()'], + '0xee1b4828': ['closeBooks()'], + '0x31a3a506': ['closeFunding()'], + '0xc71b583b': ['closeRequest()'], + '0x203c03fa': ['Coinflip()'], + '0x7879e19e': ['CollectAllFees()'], + '0xaf8b7525': ['CollectAndReduceFees(uint256)'], + '0xc27b2c2d': ['collectEarnings()'], + '0xd4d5d32a': ['collectFee()'], + '0xb17acdcd': ['collectFees(uint256)'], + '0xeeb57139': ['CollectMoney(uint256)'], + '0x4a71d469': ['collectRev()'], + '0xd9fcb31f': ['comm_channel()'], + '0xf14fcbc8': ['commit(bytes32)'], + '0xf3bb9741': ['commitmentCampaign(uint256,bytes32)'], + '0x355474d2': ['commitReading(address)'], + '0xbe4054b9': ['commitReading(address,uint256,uint256,string)'], + '0xf2f03877': ['commit(uint256,bytes32)'], + '0x3da0ac79': ['compare()'], + '0x3a96fdd7': ['compare(string,string)'], + '0x4f139314': ['compensateLatestMonarch(uint256)'], + '0xbfbc793c': ['computeNameFuzzyHash(string)'], + '0x5aa94a68': ['computeResultVoteExtraInvestFeesRate()'], + '0x6bdbf8e6': ['concat()'], + '0x89c19ddb': ['concat(string,string)'], + '0xc8f8d75d': ['Config(uint8,address)'], + '0x75cb2672': ['configure(address)'], + '0x305b73d9': ['configure(address,address,uint256,uint8,bytes32,bytes32)'], + '0x3773930e': ['ConfigureFunction(address,uint256,uint16,uint16,uint16)'], + '0x47f3d794': ['configure(uint256,uint8,uint256,uint256,uint256,uint256)'], + '0x4746cef8': ['_confirmAndCheck(address,bytes32)'], + '0xffb4c857': ['_confirmAndCheck(bytes32)'], + '0x0ae08793': ['confirmAndCheck(bytes32)'], + '0x3f3935d1': ['confirmReverse(string)'], + '0x0afa9fb9': ['contains(int256,address)'], + '0x5dbe47e8': ['contains(address)'], + '0xda4b5e29': ['contains()'], + '0x1747dfd4': ['ContractPlay()'], + '0x7e7a2fbf': ['contribute_toTheGame()'], + '0x1aadcc34': ['convertGreyGreen(uint8,uint8)'], + '0xc618d15f': ['ConvertNumbers(bytes5)'], + '0x11cd98ed': ['convertToAllTable(uint256,string)'], + '0x5020dcf4': ['convertToEach(uint256,string,uint256)'], + '0xbed1b8b9': ['convertToInt(string)'], + '0x3733ffca': ['convertTo(uint256,string,string)'], + '0x90f2c86d': ['convertToWei(uint256,string)'], + '0x276b94e1': ['copypaste()'], + '0x60726abb': ['copy()'], + '0x061ea8cc': ['countByOwner(address)'], + '0x135128c2': ['CounterPartyDeposit()'], + '0x1840f0ca': ['countVotes(uint256)'], + '0xe10e274a': ['CrazyEarning()'], + '0x4a82534b': ['create(address,address,address,uint256,uint8,uint8,uint256)'], + '0x66e98c31': ['createCoin(string,uint256,uint256,string,string,address)'], + '0x0eb0afa6': ['createDebt(address,address,uint256)'], + '0xf463edd1': ['createDocument(uint256)'], + '0xe9794dc1': ['CreateHash(uint8,string)'], + '0x5fe27ab0': ['createHKG(address)'], + '0xc88961da': ['createKingdom(string,address,address,address)'], + '0xeac116c4': ['createKingdom(string,address,address,address,address)'], + '0xa21931ea': [ + 'CreateProposal(string,string,string,uint32,string,string,string,uint32,uint32)' + ], + '0xa753d6f2': [ + 'CreateProposal(string,string,string,string,string,string,uint32,uint32)' + ], + '0x35cc59a9': ['createSchema(bytes)'], + '0x4156fdb7': ['createSwap(uint256)'], + '0x16d960b5': ['createThing(bytes32[],bytes32[],uint88)'], + '0x8ea822d8': ['createThings(bytes32[],uint16[],bytes32[],uint16[],uint88)'], + '0x72479140': ['CreateTicket(address,uint8,uint8,uint8)'], + '0x3d6a32bd': [ + 'createTradeContract(address,uint256,uint256,uint256,bool,bool)' + ], + '0x6f9a5eab': ['createTx(uint256,address,uint256)'], + '0xe1c66292': ['Create(uint32,address)'], + '0x77863b61': ['CrossWhitehatWithdraw(uint256,address)'], + '0x26a4861c': ['CROWDFUNDING_PERIOD()'], + '0xec5c9036': ['Crowdsale(address,uint256,uint256)'], + '0xe42def21': ['CryptoHill()'], + '0xeccf1b29': ['CrystalDoubler()'], + '0xbfc3d84b': ['CT()'], + '0xce845d1d': ['currentBalance()'], + '0x80c951bf': ['currentClaimPriceInFinney()'], + '0x85528394': ['currentClaimPriceWei()'], + '0xbab2f552': ['currentCycle()'], + '0x0295d71b': ['currentDepositLimit()'], + '0xda3c300d': ['currentFee()'], + '0xb8aca90b': ['CurrentGame()'], + '0xac4bd53a': ['currentLeader()'], + '0x499af77c': ['current_spin_number()'], + '0x06961560': ['DAO(address,uint256,uint256,uint256,address)'], + '0xcaed4f9f': ['DataService()'], + '0xd8915fc5': ['DCAssetBackend(bytes32,bytes32)'], + '0x306387a4': ['dealStatus(uint256)'], + '0x95669952': ['debtor(address,uint256)'], + '0xaa6be303': ['debtors(address)'], + '0x54107401': ['declareLove(string,string)'], + '0x5c19a95c': ['delegate(address)'], + '0x928a00d2': ['deleteCoin(uint256)'], + '0xe4dedc7f': ['DeleteContract()'], + '0xc0f5a9cb': ['deleteThing(bytes32[])'], + '0x07ef99a0': ['demintTokens(int256,address,uint8)'], + '0x4abb9d39': ['depletable()'], + '0xacfdfd1c': ['deploy(uint256,string,string,address)'], + '0xec2ac54e': ['deposit(address,uint256,bytes32,uint256)'], + '0xb7482509': ['deposit(address,string)'], + '0x47e7ef24': ['deposit(address,uint256)'], + '0xc5b1a53c': ['deposit(bytes16[],uint64)'], + '0xaa67c919': ['depositFor(address)'], + '0xbb3ce7fe': ['DepositHolder()'], + '0xb47fa7e0': ['DepositLimit(uint256)'], + '0x44e43cb8': ['depositRevenue()'], + '0xe241c1d9': ['deriveKey(uint256,uint256,uint256)'], + '0x9b1ad792': ['destroyToken(address,uint256)'], + '0x67fbd289': ['destroyTokens(uint256)'], + '0x2b68b9c6': ['destruct()'], + '0x41395efa': ['dgxBalance()'], + '0x56105a08': ['DgxSwap()'], + '0x594151e0': ['Dice()'], + '0x5e855f14': [ + 'Dice(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)' + ], + '0x6545bed3': [ + 'Dice(uint256,uint256,uint256,uint256,uint256,uint256,uint256)' + ], + '0x0f06670a': ['didWin(bytes32)'], + '0x91b4a0e7': ['Difficulty()'], + '0x1b3a8e6f': ['directionCount(int256,int256,int256,int256)'], + '0x0d17bc2e': ['_disallow()'], + '0x7f3bd56e': ['disburse(address,uint256)'], + '0x1f0f711f': ['discontinue()'], + '0x423e7e79': ['_dispatchEarnings()'], + '0xf240f7c3': ['dispute()'], + '0x44691f2b': ['Dispute()'], + '0x4ecd73e2': ['DistributeDividends(uint256)'], + '0x76577eae': ['distributeEarnings()'], + '0x2ef875fb': ['div10(uint256,uint8)'], + '0x058aace1': ['divest()'], + '0x11af3c68': ['divest(address)'], + '0xbb504317': ['divest(address,uint256)'], + '0x8ca17995': ['divest(uint256)'], + '0x8df554b3': ['Dividend()'], + '0x4a2b0c38': ['DividendProfit()'], + '0x0d48e8d0': ['doBalance()'], + '0xe916d0f0': ['doBalance(address)'], + '0x33fd066d': ['doBalanceFor(address)'], + '0xdfdb5f17': ['doBurn(address,uint256)'], + '0x60c311fd': ['doBurnFromContract(address,uint256)'], + '0xf1bca7a4': ['doCall(uint256)'], + '0x7fd238ba': ['doCoinage(address[],uint256[],uint256,uint256,uint256)'], + '0x8ac78c80': ['Docsign()'], + '0xddf187b0': ['dogFight()'], + '0x7997b997': ['doMelt(uint256,uint256)'], + '0xad1ef61e': ['donkeyInvested(address)'], + '0xc9bbc8c0': ['donkeyName(address)'], + '0x26161670': ['donkeyRanking(uint256)'], + '0x23509e69': ['donkeysEligibleForFees()'], + '0x37751b35': ['doTransfer(address,address,uint256)'], + '0x13220305': ['doTransferOther(address,address,address,uint256)'], + '0xdc583801': ['doubleyour5()'], + '0x4974bc27': ['download()'], + '0x9890220b': ['drain()'], + '0x0eecae21': ['draw()'], + '0x89d8ca67': ['drawPot(bytes32,bytes32)'], + '0x18433bb7': ['DrawPrepare()'], + '0xe436bdf3': ['Draws(uint256)'], + '0x4f39ca59': ['drop(bytes32)'], + '0x200538c6': ['DTE()'], + '0x5e0e2957': ['dumpOut()'], + '0xef5daf01': ['_dumpToCompany()'], + '0xaca66aec': ['DVIP()'], + '0xf245b9e4': ['DVIP(address)'], + '0xe570be18': ['DVIPBackend(address,address)'], + '0xa08b3367': ['EC()'], + '0xdb318833': ['_ecAdd(uint256,uint256,uint256,uint256,uint256,uint256)'], + '0xf47289e1': ['_ecDouble(uint256,uint256,uint256)'], + '0x913f424c': ['_ecMul(uint256,uint256,uint256,uint256)'], + '0x0c7de59d': ['edit(address,bytes,bool)'], + '0xf63da25b': ['Emailer()'], + '0x23385089': ['emitApprove(address,address,uint256)'], + '0xe3a9b508': ['EnableDisableTokenProxy()'], + '0x2c46d8d5': ['EndRound(uint256)'], + '0xacbf98a7': ['endsWith()'], + '0xf67abd87': ['entryDetails(uint256)'], + '0xd4625a3a': ['equals()'], + '0x46bdca9a': ['equal(string,string)'], + '0xfc72c1ef': ['ERC20Base(uint256)'], + '0x0bd2ae1c': ['ERW()'], + '0x22f607f6': ['Escrow()'], + '0x0bad342a': [ + 'EscrowContract(address,address,address,address,uint256,uint256,uint256,uint256)' + ], + '0x8383bfc8': ['EscrowFoundry()'], + '0x1768b436': ['ETCSurvey()'], + '0xdbf45aa3': ['EthBank()'], + '0x838445e8': ['EtherAds(address,address,address)'], + '0x1df5e755': ['Etherandom()'], + '0x384e5018': ['etherandomCallbackAddress()'], + '0xd216d55d': ['etherandomExec(bytes32,bytes32,uint256)'], + '0x1f201e39': ['etherandomExecWithGasLimit(bytes32,bytes32,uint256,uint256)'], + '0xa715ff59': ['EtherandomProxy()'], + '0x36f9f49c': ['etherandomSeed()'], + '0x70e71ea3': ['etherandomSeedWithGasLimit(uint256)'], + '0x4d561721': ['etherandomSetNetwork()'], + '0x7ca55e00': ['etherandomVerify(bytes32,bytes32,bytes32,uint256,uint256)'], + '0x29bed3bf': ['EthereumRoulette()'], + '0xd81f53fd': ['EtherId()'], + '0x50e06b57': ['Etherization()'], + '0xd409ddda': ['EtherizationUtils()'], + '0xff7f5f2a': ['EtherizationUtils2()'], + '0xf9a794ad': ['EtherLovers()'], + '0x1558ae4d': ['Etheroll()'], + '0xa08d3f83': [ + 'Etheropt(uint256,string,uint256,uint256,bytes32,address,int256[])' + ], + '0xadd43c59': ['EtherTopDog()'], + '0x356594ab': ['EtherTransfer()'], + '0x0da3e613': ['EthFactory()'], + '0xf5f6ea26': ['EthOne()'], + '0x3023d0c4': ['Ethstick()'], + '0x6f13e01b': ['EthVenturePlugin()'], + '0x4054f5de': ['EthVentures3()'], + '0x9c172f87': ['EthVentures4()'], + '0xd5171523': ['euroteambet()'], + '0x9f87acd0': ['exec(bytes32,bytes32,uint256)'], + '0xf4993bbd': ['executeEmergencyWithdrawal()'], + '0x38557648': ['executeSellOrder(address)'], + '0x4d782cbc': ['executeSellOrder()'], + '0x140b4465': ['executeSpendingRequests()'], + '0x3462f32d': ['execWithGasLimit(bytes32,bytes32,uint256,uint256)'], + '0xd4649fde': ['expire(uint256,uint8,bytes32,bytes32,bytes32)'], + '0x03cf4fd6': ['expire(uint256,uint256,uint8,bytes32,bytes32,bytes32)'], + '0x419945f8': ['ExpiringMarket(uint256)'], + '0x37930615': ['extend(bytes16[],uint64)'], + '0x6a6d31db': ['externalEnter()'], + '0xf55b23c0': ['externalLeave()'], + '0xe2056c46': ['ExtraBalToken()'], + '0x7ef95c6f': ['extractAccountAllowanceRecordLength(address)'], + '0x4de162e4': ['extractAccountLength()'], + '0x727089f1': ['extractAllowanceLength()'], + '0x8f731077': ['extractAllowanceRecordLength(address)'], + '0xc8117b5b': ['extractBalanceOfLength()'], + '0x1cf43b63': ['extractExportFeeChargeLength()'], + '0xa056469a': ['extractFeeLength()'], + '0xb5a6c525': ['extractFrozenAccountLength()'], + '0xd1da09ee': ['extractImportFeeChargeLength()'], + '0x2885b593': ['extractMasterKeyIndexLength()'], + '0x981a60f5': ['extractNameFromData(bytes)'], + '0xb764e273': ['failSend()'], + '0xc57a050e': ['fairandeasy()'], + '0xa5e62f02': ['fallbackRP()'], + '0x93e02d13': ['FallenLeaders()'], + '0xd3732642': ['FastRealisticPyramid()'], + '0xc5096a69': ['feeFor(address,address,uint256)'], + '0x6860fd58': ['Fees(uint256)'], + '0x5b151fd2': ['fifty_fifty()'], + '0x75438e49': ['fillGas()'], + '0x884b5dc2': ['fill(uint256[])'], + '0x7ff729fc': ['fillUpProject(uint256,uint256)'], + '0xbf12165e': ['fillUpSlot(uint256,uint256)'], + '0x5fa513d5': ['findPtr(uint256,uint256,uint256,uint256)'], + '0x70d53be5': ['find()'], + '0xc9bd2893': ['fines()'], + '0x2cce4abe': ['_finishNoCallback()'], + '0x113e6b66': ['fipsAddToLedger(bytes20,address)'], + '0xaa8dea8c': ['fipsAddToLedger(bytes20,address,bytes)'], + '0xa289673b': ['fipsChangeOwner(bytes20,address,address)'], + '0x1dcb304b': ['fipsGenerate()'], + '0x7910085d': ['fipsIsRegistered(bytes20)'], + '0x3ae7cdfa': ['fipsLegacyRegister(bytes20[],address)'], + '0xdfce8ac3': ['fipsLegacyRegister(bytes20,address,bytes)'], + '0x5cb18a6d': ['fipsLegacyRegisterMulti(bytes20[],address,bytes)'], + '0x3def449b': ['FipsNotary()'], + '0x7620f4bb': ['fipsNotaryLegacy68b4()'], + '0x5084da18': ['fipsOwner(bytes20)'], + '0x3df76482': ['fipsPublishData(bytes20,bytes)'], + '0xfba06849': ['fipsPublishDataMulti(bytes20[],bytes)'], + '0x74d4ab27': ['fipsRegister()'], + '0x419ffa03': ['fipsRegister(address)'], + '0xb16562fe': ['fipsRegister(address,bytes)'], + '0x1531c267': ['fipsRegisterMulti(uint256,address,bytes)'], + '0x3dc02266': ['fipsRegister(uint256)'], + '0x2f62a6ff': ['fipsRegister(uint256,address,bytes)'], + '0xc12af1ce': ['fipsRegister(uint256,bytes)'], + '0x2fa00e58': ['fipsTransfer(bytes20,address)'], + '0x42402c2c': ['fipsTransferMulti(bytes20[],address)'], + '0x9e9d3aa4': ['FirstBloodToken(address,address,uint256,uint256)'], + '0x3df4ddf4': ['first()'], + '0xe87df70e': ['fivetimes()'], + '0x912de8de': ['fixBalance()'], + '0xf1c760ae': ['fixBalanceInternal(address)'], + '0x3369dace': ['flipTheCoinAndWin()'], + '0x6b9f96ea': ['flush()'], + '0x446a7974': ['Fokitol()'], + '0x6a5da6e5': ['followCampaign(uint256)'], + '0x384b1393': ['follow(uint256)'], + '0x7cf0ffcb': ['forceDivestAll()'], + '0x29e206bd': ['forceDivestAll(bool)'], + '0x232523e8': ['forceDivestOfAllInvestors()'], + '0x51404cbe': ['forceDivestOfOneInvestor(address)'], + '0x93feb13b': ['ForceSendHelper(address)'], + '0x11b9fee8': ['ForkChecker(uint256,bytes32)'], + '0x16c72721': ['forked()'], + '0xd264e05e': ['forward()'], + '0xa4d575ce': ['_forward(address,bytes)'], + '0xac562666': ['freezeCoin()'], + '0xb466b76f': ['fresh()'], + '0xb72e717d': ['fromAddress(address)'], + '0x891de9ed': ['fromTLA(string)'], + '0x3c067945': ['fundBalance()'], + '0x43243797': ['fundsOf(address)'], + '0xca708230': ['funnel()'], + '0xfc108f70': ['GamblerPerAddress(address)'], + '0xefa7e56b': ['GameEnds()'], + '0x2143da91': ['GameOfThrones()'], + '0xa10edc55': ['GeneralPurposeProfitSplitter()'], + '0x4d70d1d7': ['generateId(uint256)'], + '0x6f6c0244': ['generateShortLink()'], + '0x419db07b': ['generousFee()'], + '0xfa7d68f1': ['getAccountInfo(uint256,uint256)'], + '0x10082bff': ['getActorBillXdetail(address,uint256,bool)'], + '0x04fc11d5': ['getActual()'], + '0x21f8a721': ['getAddress(bytes32)'], + '0x6795dbcd': ['getAddress(bytes32,string)'], + '0x42c69566': ['get_address(address,string)'], + '0xe7b48f74': ['get(int256,address)'], + '0x579cdf17': ['getAdminName(address)'], + '0xc8edf65e': ['GetAndReduceFeesByFraction(uint256)'], + '0xc6ed8e1b': ['getApprovedProxys()'], + '0xf9cc0605': ['getAvailable()'], + '0x12065fe0': ['getBalance()'], + '0x1177892f': ['getBalanceByAdress(address)'], + '0x565a2e2c': ['getBeneficiary()'], + '0xa6afd5fd': ['getBets()'], + '0x061e494f': ['getBet(uint256)'], + '0x8c98117c': ['getBill(uint256,uint256)'], + '0xe422ebe9': ['getBot()'], + '0x618fa9ce': ['getBotBillingIndex(uint256,uint256)'], + '0x4ae9af61': ['getBotStats(uint256,uint256)'], + '0x5f70d9ac': ['getBot(uint256)'], + '0xc06c4474': ['get_burned(bytes32)'], + '0xc00ca383': ['getByOwner(address,uint256)'], + '0x8eaa6ac0': ['get(bytes32)'], + '0xd120a284': ['getBytesFromNumbers(uint8[3])'], + '0x1f6e5117': ['getCallbackAddress()'], + '0x769dc523': ['GetCategoryNumber(bytes4)'], + '0x7281854d': ['GetCategoryValue(uint8)'], + '0xc88cc6ac': ['getCertification(address)'], + '0x777feff5': ['getCertificationDbAtIndex(uint256)'], + '0x808ab1d6': ['getCertificationDbCount()'], + '0xfd260dfc': ['getCertificationDbStatus(address)'], + '0xde629235': ['getCertificationDocumentAtIndex(address,uint256)'], + '0xd5582205': ['getCertifiedStudentAtIndex(uint256)'], + '0x038461ea': ['getCertifiedStudentsCount()'], + '0x2f695053': ['getCertifierAtIndex(uint256)'], + '0x56d73ad1': ['getCertifierDb()'], + '0x6e63015c': ['getCertifiersCount()'], + '0x05b765ea': ['getCertifierStatus(address)'], + '0x045236b4': ['getChainyData(string)'], + '0x919edc7c': ['getChainySender(string)'], + '0xe8b13c44': ['getChainyTimestamp(string)'], + '0x233120aa': ['getChainyURL()'], + '0xd7130651': ['getCity(uint256)'], + '0xd0068f80': ['getClient(uint256)'], + '0x3aa94b1d': ['getCoinStats(uint256)'], + '0xda311588': ['getCoin(uint256)'], + '0xe65d6b49': ['getCommission()'], + '0x69bcdb7d': ['getCommitment(uint256)'], + '0xf896503a': ['getConfigAddress(bytes32)'], + '0xea3ebae6': ['getConfigBool(bytes32)'], + '0x62c7855b': ['getConfigBytes(bytes32)'], + '0xb44bd51d': ['getConfig(string)'], + '0x5c1b3ca1': ['getConfigUint(int256,bytes32)'], + '0xd408746a': ['GetContractAddr()'], + '0xd3edcb5b': ['getCreditorAddresses()'], + '0x81064e2d': ['getCreditorAmounts()'], + '0x77c78df9': ['getCurrentLevel()'], + '0x2bf4e53d': ['getCurrentShareholders()'], + '0x329bfc33': ['getCurrentWinner()'], + '0x152cf9db': ['getDataPoint(int256,uint256,uint256)'], + '0xcf69df28': ['getDataRequestLength()'], + '0x88f53db1': ['getDataRequest(uint256)'], + '0xd2b0d554': ['getDisclaimer()'], + '0x80ede329': ['getDocumentDetails(uint256)'], + '0x16e55626': ['getDogName(address)'], + '0x1a7a98e2': ['getDomain(uint256)'], + '0xbe6307c8': ['getDraw(uint256)'], + '0x2fa7cbfb': ['getExecCost(uint256)'], + '0x752bacce': ['getExecPrice()'], + '0xba1162d7': ['getFmLength()'], + '0xd63547e6': ['GetFreeCnt()'], + '0x4a7e049e': ['getFullCompany(address,uint256)'], + '0x3e853128': ['getGasForXau(address)'], + '0x455259cb': ['getGasPrice()'], + '0x75608264': ['get_hash(uint8,bytes32)'], + '0xbba91ea7': ['getHomeadvIndex(uint256)'], + '0x24fc65ed': ['getId(uint256,uint256)'], + '0xb7de47d3': ['getIndex(uint256,uint256)'], + '0x2b98222e': ['getInstitutionByAddress(address)'], + '0x6da1833c': ['getInstitutionByName(string)'], + '0x728af7ec': ['getInterest(uint256,uint256)'], + '0x0a80ef45': ['getIsClosed()'], + '0x0ed21029': ['getIssueAssignee(uint256,bytes32)'], + '0x706dfe54': ['getIssueState(uint256,bytes32)'], + '0xc5bf339c': ['getLastNonPublished()'], + '0x65fa2f7f': ['getLastPrice(uint256)'], + '0x89f4ed7a': ['getLastTag(uint256)'], + '0x29a065bd': ['getLOg(uint256)'], + '0xe0e3ba5a': ['getLosesShare(address)'], + '0x550ed1f0': ['getMaxBetAmount()'], + '0x82a5285d': ['getMinBetAmount()'], + '0x5af73f3f': ['getMinimalBalance(uint256,address)'], + '0x90daaf67': ['getMinimalDeposit()'], + '0xf909d60d': ['getMinimumGasLimit()'], + '0x724ae9d0': ['getMinInvestment()'], + '0xa538d287': ['getMinMax()'], + '0x686e8aaa': ['GetMoney()'], + '0x3cc86b80': ['GetMoney(uint256,address)'], + '0x50ab6f7f': ['getMsgs()'], + '0xc1d4f708': ['getMwLength()'], + '0xcfb3a493': ['getMyBounty(uint256)'], + '0xb484e532': ['getMyMsg()'], + '0xc003b082': ['getMyPlayerID()'], + '0x36ffa905': ['getMyProposals()'], + '0x0645b5d5': ['getMyShareholderID()'], + '0x3e83fe36': ['getMyShares()'], + '0xea1bf386': ['getNextSellerBOTdata(uint256)'], + '0x2ade6c36': ['getNodeAddress(bytes32)'], + '0xbbe4fd50': ['getNow()'], + '0x1c895915': ['getNumberOfPayments(uint256)'], + '0x5819dde2': ['getNumbersFromBytes(bytes3)'], + '0x017972af': ['getNumbersFromHash(bytes32)'], + '0x06638e92': ['GetNumbersFromHash(bytes32)'], + '0x57ee24af': ['getNum(bytes32,uint256)'], + '0xb39a64cd': ['getNumCalled()'], + '0x52200a13': ['getNumHolders(uint256)'], + '0x72ea4b8c': ['getNumInvestors()'], + '0xa8893a6e': ['getNumOfSalesWithSameId(bytes16)'], + '0x531c1b33': ['getOperatingBudget()'], + '0x09574810': ['getOperationsNumber()'], + '0x202e3924': ['getOperation(uint256)'], + '0xfaa1a8ff': ['getOwnedBot(address,uint256)'], + '0x0ae50a39': ['GetOwner()'], + '0xe74ffbd5': ['getPart(bytes32,uint256)'], + '0xd085e66e': ['GetPart(bytes32,uint256)'], + '0xe42d5be0': ['getPaymentOf(address)'], + '0x5a825cbb': ['getPayment(uint256,uint256)'], + '0xe56556a9': ['getPlayerID(address)'], + '0x953aa435': ['GetPrice(uint8)'], + '0x116c6eab': ['getProfitShare(address)'], + '0x7486a8e3': ['get_publisher(bytes32)'], + '0x6a28db13': ['getQrLength()'], + '0x163aba3c': ['getQueryFee()'], + '0xf1b3f968': ['getRaceEndBlock()'], + '0xcd4b6914': ['getRandom(uint256)'], + '0x7bcd7fad': ['getRecordAtIndex(uint256)'], + '0xb719d1d0': ['getRegInfo(address)'], + '0x052b2aa7': ['getRegistrants()'], + '0xadd4c784': ['getResult(bytes32)'], + '0x7332b520': ['getRewardsCount(uint256)'], + '0x85dd2148': ['getSaleDate(bytes16)'], + '0xac92fdb5': ['getSaleDate(bytes16,uint256)'], + '0xd239ea8b': ['getSchemasLenght()'], + '0x288c6ed2': ['getSeedCost(uint256)'], + '0x9183fd01': ['getSeedPrice()'], + '0x347632e8': ['getShareholderAdressByID(uint256)'], + '0x308d6613': ['getSignData(uint256,uint8)'], + '0xb36a0b15': ['getSignDetails(uint256,uint8)'], + '0x28dcfdac': ['getSignsCount(uint256)'], + '0x842bc37b': ['GetSmallCotractIndex(address)'], + '0xafa293d4': ['getSource()'], + '0xe9e7a667': ['get_stake(bytes32)'], + '0x22b0f6ee': ['getStatusOfPayout(uint256)'], + '0x9a0af2ec': ['getStLength()'], + '0x693ec85e': ['get(string)'], + '0x4a0d89ba': ['getSwap(uint256)'], + '0x7ac26aeb': ['getTag(string,uint256)'], + '0xdf300b46': ['getThing(bytes32[])'], + '0x55b62dcf': ['getThresold(uint256)'], + '0x002a5cc9': ['getTicketHolders(uint256)'], + '0x9f0e3107': ['get_timestamp(bytes32)'], + '0x82b2e257': ['getTokenBalance()'], + '0xacab021c': ['getTOS(address)'], + '0x12b58349': ['getTotalBalance()'], + '0xc4e41b22': ['getTotalSupply()'], + '0xcaa648b4': ['getTotalValue()'], + '0xf709dd51': ['getTrademark()'], + '0x9bb0e4df': ['getUint(int256,bytes32,string)'], + '0x74e4435f': ['getUserAddress(uint256,bytes32)'], + '0xa2bb5d48': ['get_username(address)'], + '0x6de00927': ['GetUserRank(uint8,address)'], + '0xff981099': ['getVotes(uint256)'], + '0xffb1a6cb': ['getWins(address)'], + '0x4ae8c55f': ['getWwLength()'], + '0xfb9a4595': ['GitHubBounty()'], + '0x0b7373d6': ['giveAllBack()'], + '0x04706fdf': ['giveContributionsBackProfitBugged()'], + '0xb5299ca6': ['giveMeat()'], + '0x9e7b8d61': ['giveRightToVote(address)'], + '0x35ae41c9': ['godAutomaticCollectFee()'], + '0x691bfc89': ['goods(uint16,uint256)'], + '0x7c25f260': ['Government()'], + '0xbb6a0853': ['GreedPit()'], + '0x92ba4ba6': ['GridMember(string,uint256,bool,address,address)'], + '0x3cc7790a': ['GSI()'], + '0xa1c95ac2': ['GSIToken(uint256,string,uint8,string,address)'], + '0x75f96ead': ['Guess(uint256)'], + '0xdf143fb7': ['HackerGold(address)'], + '0x5ed7ca5b': ['halt()'], + '0x4f28af6a': ['handleBet(uint256)'], + '0xcb96012e': ['hashTo256(bytes32)'], + '0x650955d4': ['HashToken()'], + '0xa1add510': ['hasRelation(bytes32,bytes32,address)'], + '0x06f36cc9': ['helpBlue()'], + '0x353928d8': ['helpRed()'], + '0xce373b95': ['heroOfThePit()'], + '0xaeeb96af': ['Highlander()'], + '0x7eb69ba1': ['hint(int256,bytes32,string,bytes20)'], + '0xc98031be': ['hintURL(int256,bytes32,string)'], + '0xef4ffee2': ['Honestgamble()'], + '0xa6027d53': ['IconomiTokenTest(uint256,string,uint8,string,uint256)'], + '0xb98fdc36': ['IconomiToken(uint256,string,uint8,string,uint256)'], + '0xdaf22f4d': ['identify(bytes32)'], + '0xaf640d0f': ['id()'], + '0xf7c3ee7a': ['immortality()'], + '0x602acca1': ['InchainICO(address[],uint256)'], + '0xa4beffa7': ['increaseInvestment()'], + '0xcab5c0f1': ['_incrementState()'], + '0x1e8c72b4': ['incrUserAvailBal(address,uint256,bool)'], + '0x3d5db1c2': ['incrUserOnholdBal(address,uint256,bool)'], + '0x22686250': ['index(int256,uint256)'], + '0x1f13de92': ['inEther(uint256)'], + '0x9334ab61': ['Infos()'], + '0x4a1f0bf6': ['inheritToNextGeneration(address)'], + '0x2cc0b254': ['init(address,bytes32)'], + '0x87ebd76c': ['initContract(string,string,uint256,uint256)'], + '0x23584a21': ['initStats(string,address,uint256)'], + '0x98eaca94': ['inKissBTC(uint256)'], + '0xa0469b02': ['inputToDigit(uint256)'], + '0xfeaa29d8': ['insertProfitHere()'], + '0x46af23f5': ['InstantLottery(address,address,bool,address)'], + '0xf83d96c1': ['InsuranceAgent()'], + '0x8cecf66e': ['_inverse(uint256)'], + '0xadfe6b80': ['InvestAdd()'], + '0x391f2e96': ['InvestCancel()'], + '0x4f013184': ['investInTheSystem()'], + '0xc4321adb': ['investInTheSystem(uint256)'], + '0x2afb21bc': ['InvestWithdraw()'], + '0x76285b5b': ['_is360thDay()'], + '0x74eb9b68': ['isAccountLocked(address)'], + '0x1cf52f2b': ['isActiveRegistrant(address)'], + '0x24d7806c': ['isAdmin(address)'], + '0xfc1f7652': ['_isBoardMember(address)'], + '0xda7d0082': ['isCertification(address,bytes32)'], + '0x5afa5036': ['isCertified(address)'], + '0x1c2353e1': ['isCertifier(address)'], + '0x37b0574a': ['isClassic()'], + '0xc2b6b58c': ['isClosed()'], + '0x57eaeddf': ['_isContract()'], + '0x2f553d31': ['isCreated(bytes32)'], + '0x5445e38c': ['_isCycleValid(uint256)'], + '0x88eb7af7': ['_isHuman()'], + '0xaa51793c': ['isLosingBet(uint256)'], + '0x42f6e389': ['isModule(address)'], + '0x6534b4e2': ['IsPayoutReady__InfoFunction(bytes32)'], + '0x245a6f74': ['isProxyLegit(address)'], + '0x3e5cee05': ['issueIOU(string,uint256,address)'], + '0x05d87fe2': ['issueLetterOfCredit(uint256,uint256,uint256)'], + '0x40fdf515': ['issuetender(address,uint256,uint256)'], + '0x475a9fa9': ['issueTokens(address,uint256)'], + '0x4adcbd19': ['isThisHardforkedVersion()'], + '0xaf5610dd': ['isThisPreforkVersion()'], + '0x7c4c27c8': ['isThisPuritanicalVersion()'], + '0x4209fff1': ['isUser(address)'], + '0x04d10f1c': ['isValidChainyJson(string)'], + '0x6662e4be': ['isWinningBet(uint256)'], + '0x99aeade3': ['iterateTable(uint256,uint256)'], + '0x3b46a7df': ['ivote(bool)'], + '0x0138e31b': ['_jAdd(uint256,uint256,uint256,uint256)'], + '0xed64bea4': ['JamCoin()'], + '0x5f972df8': ['_jDiv(uint256,uint256,uint256,uint256)'], + '0x9743dfc1': ['jesterAutomaticCollectFee()'], + '0x5b764811': ['_jMul(uint256,uint256,uint256,uint256)'], + '0x4a7b26ec': ['join_game(uint256)'], + '0x1ecfe64d': ['_jSub(uint256,uint256,uint256,uint256)'], + '0x691fb8ea': ['jumpIn()'], + '0xc53ad76f': ['Kardashian()'], + '0x775dec49': ['keccak()'], + '0xbe26733c': ['Kill()'], + '0x73abecbb': ['kill1()'], + '0x2bb685bc': ['kill2()'], + '0x179b73da': ['killBoardProposal(uint256,address)'], + '0xb0c7f709': ['kingAutomaticCollectFee()'], + '0x7e81b6aa': ['KingdomFactory()'], + '0x5e68ac2c': [ + 'Kingdom(string,address,address,address,uint256,uint256,uint256,uint256,uint256)' + ], + '0x31ae0019': ['KissBTC()'], + '0x07e00bcb': ['kissBTCCallback(uint256,uint256)'], + '0x47799da8': ['last()'], + '0x7075b1d8': ['latestMonarchInternal()'], + '0xfa6d373c': ['LeaderHash()'], + '0x9fb25d9e': ['LeaderMessage()'], + '0x166c4b85': ['len(bytes32)'], + '0xd95a2d42': ['lendGovernmentMoney(address)'], + '0x56d88e27': ['len()'], + '0xfe71aec5': ['LittleCactus()'], + '0x7b647652': ['LittleEthereumDoubler()'], + '0xf83d08ba': ['lock()'], + '0xe8d1e961': ['lockAccount(uint256)'], + '0x3a7d280c': ['login(string)'], + '0x4cbee813': ['logout(string)'], + '0x41304fac': ['log(string)'], + '0x71e2d919': ['lol()'], + '0x3fd1f232': ['LookAtAllTheseTastyFees()'], + '0xf7bd2361': ['LookAtBalance()'], + '0x25d4bdeb': ['LookAtCollectedFees()'], + '0x7ee65635': ['LookAtDepositsToPlay()'], + '0xb0ecca8f': ['LookAtLastTimePerZone(uint256)'], + '0xb1c6517a': ['LookAtNumberOfPlayers()'], + '0xdfca2f53': ['LookAtPrizes()'], + '0xa9fbc614': ['lookupTicketHolder(uint256)'], + '0xba13a572': ['lottery()'], + '0x21bb79fe': ['luckyDogInfo()'], + '0xb74bc710': ['LuckyDoubler()'], + '0x5a2ee019': ['m()'], + '0x8af49ab7': ['maintain(uint256,uint256)'], + '0x561e91a1': ['makeBet()'], + '0x1077f06c': ['makeClaim(uint256)'], + '0x059a500c': ['makeDeposit(uint256)'], + '0x3df16377': [ + 'make_move_and_claim_victory(uint256,uint8,uint8,uint8,uint8,uint8,uint8,uint8)' + ], + '0xa35cfa22': ['make_move(uint256,uint8,uint8,uint8,uint8)'], + '0x2f1e4968': ['makeNewProposal(string,uint256)'], + '0x8b543b80': ['maximumCredit(address)'], + '0x11fe773d': ['memcpy(uint256,uint256,uint256)'], + '0x62be3172': ['Message(address,address,address,string)'], + '0x0257c48c': ['meta(bytes32,bytes32)'], + '0x7958533a': ['meta(uint256,bytes32)'], + '0x8f8bde82': ['MicroDAO()'], + '0x1e701780': ['MICRODAO(address,uint256,uint256,uint256,address)'], + '0x026993e0': ['Midas(address,address)'], + '0xfa968eea': ['minBetAmount()'], + '0xd10e99fe': ['mint(int256,bytes32)'], + '0x3a7fb796': ['mintGreen(int256,address,uint256)'], + '0x77ceded8': ['mintGrey(int256,address,uint256)'], + '0xf41bfa9e': ['mint(int256,uint256,string)'], + '0x411c4e72': ['ModifyFeeFraction(uint256)'], + '0xa20c404f': [ + 'ModifySettings(uint256,uint256,uint256,uint256,uint256,uint256,uint256)' + ], + '0x689b3e2d': ['Moonraker(address,address)'], + '0x5837e083': ['move_history(uint256)'], + '0xd8a8e03a': ['move(uint256,address)'], + '0x231944e2': ['moveUnits(uint256,uint256,uint256[])'], + '0x33f472b9': ['MPO()'], + '0xf714de9c': ['MultiAccess()'], + '0x4f60f334': ['multiAccessAddOwner(address)'], + '0x092a2e37': ['multiAccessAddOwnerD(address,address)'], + '0x69a5e902': ['multiAccessCall(address,uint256,bytes)'], + '0x8b9726c1': ['multiAccessCallD(address,uint256,bytes,address)'], + '0x9bd99195': ['multiAccessChangeOwner(address,address)'], + '0x6c494843': ['multiAccessChangeOwnerD(address,address,address)'], + '0x6d522b19': ['multiAccessChangeRequirementD(uint256,address)'], + '0x62891b5d': ['multiAccessChangeRequirement(uint256)'], + '0x446294ad': ['multiAccessGetOwners()'], + '0xeb7402f5': ['multiAccessHasConfirmed(bytes32,address)'], + '0xe419f189': ['multiAccessIsOwner(address)'], + '0x73f310df': ['multiAccessRemoveOwner(address)'], + '0x5a74dee5': ['multiAccessRemoveOwnerD(address,address)'], + '0x7ed19af9': ['multiAccessRevoke(bytes32)'], + '0xd1b4ff7e': ['multiAccessRevokeD(bytes32,address)'], + '0xd1cf113e': ['multiAccessSetRecipient(address)'], + '0x7429f1eb': ['multiAccessSetRecipientD(address,address)'], + '0x30677b83': ['multiplierFactor()'], + '0x9d7d6667': ['multipliers()'], + '0xfbeaebc6': ['murder()'], + '0x98391c94': ['muteMe(bool)'], + '0x0bd089ab': ['MyAdvancedToken(uint256,string,uint8,string,address)'], + '0xc95e81cb': ['MyBet(uint8,address)'], + '0x6e658fbe': ['myFundsExpireIn(uint256)'], + '0x089327de': ['MyToken()'], + '0x041d0c0b': ['MyTokenLoad(uint256,string,uint8,string,address)'], + '0x1d2bca17': ['MyToken(uint256,string,uint8,string)'], + '0x2e52d606': ['n()'], + '0x19350aea': ['nameFor(address)'], + '0x3bcf7d22': ['newBribedCitizen(address)'], + '0xba487e62': ['newCampaign(uint32,uint96,uint16,uint16)'], + '0x927ed13a': ['newClient(uint256,address)'], + '0x1df473bc': ['newContract(bytes)'], + '0xf3dd3d8a': ['newCurrency(string,string,uint8)'], + '0x78ae88d1': ['newDeal(uint256,uint256,uint256,uint256,uint256)'], + '0x7c69b5d1': ['NewDeposit(uint256)'], + '0xc853c03d': ['newDraw(uint256,uint8[3],uint256,uint256,uint256,uint256)'], + '0xdcff5581': ['NewFeeAddress(address)'], + '0x66ad484c': ['newfirst_player(address)'], + '0x7d03f5f3': ['newGame()'], + '0xd9e7ee1c': ['new_game(uint256,uint256)'], + '0x1d71a1cd': ['newIncome(string)'], + '0xfb099c84': ['newInvestor()'], + '0x4316abbb': ['newJester(address)'], + '0x9a8f09bd': ['newKing(address)'], + '0x9229c504': ['new_mainPlayer(address)'], + '0x2fac1a54': ['newOrder(bool,uint256,uint256,uint256,uint256)'], + '0x85952454': ['newOwner(address)'], + '0x3baf4e1e': ['newPayment(uint256,uint256)'], + '0x71589d6b': ['newponzi()'], + '0x4f24186a': ['newProposal(string)'], + '0xa07daa65': ['newRequest(uint256)'], + '0x025bbbe5': ['newSale(bytes16,uint256,uint256)'], + '0x97bb2a63': ['newvow(uint256,address)'], + '0xf28386bf': ['Nexium()'], + '0xab73e316': ['next(address)'], + '0x727b1cd6': ['next_draw(bytes32,uint256,uint256,uint256,uint256,uint256)'], + '0x332f93a9': ['nextPayoutGoal()'], + '0x47e40553': ['nextRound()'], + '0xd1bf9aba': ['nextRune()'], + '0xb3cb8885': ['nextUnderdogPayout()'], + '0xb3a2a999': ['nextWithdrawal(bytes16)'], + '0xa668d7c9': ['NiceGuyPonzi()'], + '0x0908178f': ['NoFeePonzi()'], + '0xac20902e': ['NormalizeMoney()'], + '0x305075db': ['NormalizeRanks()'], + '0xecb4136e': ['NotAnotherPonzi()'], + '0x58d3b617': ['Notifier(string)'], + '0xfa4e5e5a': ['notify(uint8,string,string)'], + '0xdea06188': ['NumberOfBlockAlreadyMined()'], + '0x892c0214': ['NumberOfCurrentBlockMiners()'], + '0x85233869': ['NumberOfMiners()'], + '0xdf811d7d': ['numberOfPlayersInCurrentRound()'], + '0xdf06f906': ['numBets()'], + '0xca35271c': ['numDebtors(address)'], + '0x902e64e5': ['Oath()'], + '0xa1920586': ['offer(uint256,uint256)'], + '0x901717d1': ['one()'], + '0xe671f510': ['onEtherandomExec(bytes32,bytes32,uint256)'], + '0x041fe13d': ['onEtherandomSeed(bytes32,bytes32)'], + '0xa5eb7a4e': ['operated()'], + '0x9549355e': ['oracalizeReading(uint256)'], + '0x9a828a71': ['oracalizeReading(uint256,string)'], + '0x053c351b': ['oraclize_getPrice(string)'], + '0xabe9f569': ['oraclize_getPrice(string,uint256)'], + '0xc8e55708': ['oraclize_query(string,string[1])'], + '0x871113c3': ['oraclize_query(string,string[1],uint256)'], + '0x044d0b06': ['oraclize_query(string,string[2])'], + '0xa6bf3df0': ['oraclize_query(string,string[2],uint256)'], + '0x9b9ba572': ['oraclize_query(string,string[3])'], + '0xae404996': ['oraclize_query(string,string[3],uint256)'], + '0x16d9356f': ['oraclize_query(string,string[4])'], + '0xbc5ff5e1': ['oraclize_query(string,string[4],uint256)'], + '0xbd9a5673': ['oraclize_query(string,string[5])'], + '0xb6ce5581': ['oraclize_query(string,string[5],uint256)'], + '0x14167bf0': ['oraclize_query(string,string[])'], + '0xe50a3bb1': ['oraclize_query(string,string[],uint256)'], + '0x0ff4f160': ['oraclize_query(uint256,string,string[1])'], + '0x77ac3da5': ['oraclize_query(uint256,string,string[1],uint256)'], + '0xa8c3ec48': ['oraclize_query(uint256,string,string[2])'], + '0x29a6f31b': ['oraclize_query(uint256,string,string[2],uint256)'], + '0xec6afc22': ['oraclize_query(uint256,string,string[3])'], + '0xfb114f57': ['oraclize_query(uint256,string,string[3],uint256)'], + '0x2ff92323': ['oraclize_query(uint256,string,string[4])'], + '0x0494630f': ['oraclize_query(uint256,string,string[4],uint256)'], + '0x6510ef4d': ['oraclize_query(uint256,string,string[5])'], + '0x00a94b6e': ['oraclize_query(uint256,string,string[5],uint256)'], + '0xdc206e5f': ['oraclize_query(uint256,string,string[])'], + '0xa2b5591c': ['oraclize_query(uint256,string,string[],uint256)'], + '0x83a51ad0': ['oraclize_setConfig(bytes32)'], + '0x01095962': ['oraclize_setCustomGasPrice(uint256)'], + '0x6b1cb549': [ + 'orderMatch(uint256,uint256,uint256,int256,uint256,uint256,address,uint8,bytes32,bytes32,int256)' + ], + '0xbd858288': [ + 'orderMatch(uint256,uint256,int256,uint256,uint256,address,uint8,bytes32,bytes32,int256)' + ], + '0x17961d0f': ['ord()'], + '0x16bac350': ['overthrow(string)'], + '0xe2894a8a': ['OwnerAnnounce(string)'], + '0x4f44728d': ['ownerChangeOwner(address)'], + '0xad04592e': ['owner_deposit()'], + '0xd6e0bf29': ['OwnerDeposit()'], + '0xd263b7eb': ['ownerkill()'], + '0x6eacd48a': ['ownerPauseGame(bool)'], + '0x4b7fcee7': ['ownerPausePayouts(bool)'], + '0xcf832ce2': ['ownerRefundPlayer(bytes32,address,uint256,uint256)'], + '0xa27c672a': ['owner_reveal_and_commit(uint8,bytes32,bytes32)'], + '0x392327b5': ['owner_set_fraction(uint256)'], + '0x268d50fe': ['ownerSetHouseEdge(uint256)'], + '0x5e968a49': ['ownerSetMaxProfitAsPercentOfHouse(uint256)'], + '0x6cdf4c90': ['ownerSetMinBet(uint256)'], + '0xd207e757': ['ownerSetOraclizeSafeGas(uint32)'], + '0x8b64d70e': ['owner_set_time_limit(uint256)'], + '0x31375242': ['ownerSetTreasury(address)'], + '0xf738e5ca': ['ownerTakeProfit()'], + '0x758971e8': ['ownerTakeProfit(bool)'], + '0x7ac37d58': ['ownerTransferEther(address,uint256)'], + '0x150ad2a8': ['owner_transfer_ownership(address)'], + '0x26da8e17': ['ownerUpdateCostToCallOraclize(uint256)'], + '0xb33926cb': ['owner_withdraw(uint256)'], + '0xf7bc39bf': ['owns(address)'], + '0x88c3ba85': ['ParallelGambling()'], + '0xf65c4d42': ['Participate(uint256)'], + '0x1b9265b8': ['pay()'], + '0x18b749c4': ['payEther(uint256)'], + '0x4d268ddd': ['payImporterBankForGoodsBought()'], + '0xff08d2b0': ['PayMiners()'], + '0x85db2dda': ['PayoutQueueSize()'], + '0xe0fe075e': ['payoutReady()'], + '0x081e806d': ['PayOut(uint256)'], + '0xb2310cc5': ['payRequstedSum(uint256,uint256)'], + '0xb821f815': ['pay_winner(uint256)'], + '0xabf74a93': ['pitFee()'], + '0x43046844': ['placeBet(uint8)'], + '0xa4406bcd': ['placeSellOrder(uint256,uint256)'], + '0xb1cc4348': ['placeWager()'], + '0x71b6663e': ['play1(address,uint256)'], + '0x2ddbc04a': ['play2(address,uint256)'], + '0xdb18c972': ['play4(address,uint256)'], + '0xf0e10c0d': ['play(address,uint256)'], + '0xc7a1865b': ['play(bytes32)'], + '0x3e4c0c82': ['player_1(uint256)'], + '0x1ef0625b': ['player_2(uint256)'], + '0xc068eae0': ['player_collect_winnings(uint256)'], + '0xa4fde8bc': ['player_declare_taking_too_long()'], + '0x3c314a91': ['playerGetPendingTxByAddress(address)'], + '0x46b04e53': ['PlayerInfoPerZone(uint256,uint256)'], + '0x63aea3e0': ['PlayerInfo(uint256)'], + '0xeace4827': ['player_make_bet(uint8)'], + '0xdc6dd152': ['playerRollDice(uint256)'], + '0x24fb563f': ['PlayerTickets(address,uint256,uint256)'], + '0xa5f4af33': ['playerWithdrawPendingTransactions()'], + '0x39b333d9': ['Play(uint8,uint8,uint8,uint8)'], + '0x4c0eceb5': ['plusOnePonzi()'], + '0xe6cbcba9': ['PlusOnePonzi()'], + '0xd1f0bb2d': ['populateAllowedFreeExchanges()'], + '0x3570c2ee': ['PosRewards()'], + '0xb45105b2': ['post(string,address,string)'], + '0xc6a17d2b': ['pow10(uint256,uint8)'], + '0x2c02d622': ['precalculate()'], + '0x13bd4e2c': ['_prepareAndSendReward()'], + '0xf81d087d': ['prepareLottery()'], + '0xe6c1beb4': ['prepend(address)'], + '0xf8018a79': ['prepend(address,address)'], + '0x6bae05cf': ['preRegister(address)'], + '0x45788ce2': ['prev(address)'], + '0xa035b1fe': ['price()'], + '0x1288c42a': ['Prism()'], + '0x22dc36e2': ['processed(uint64)'], + '0x61aa8d93': ['processFee()'], + '0x5c52e51e': ['processPayout()'], + '0x80acaafb': ['profitDistribution()'], + '0xe1f5ebc5': ['_projectAddNew(address,uint256)'], + '0x6a3c1198': ['_projectCancelNew()'], + '0xa055fe64': ['_projectCommitNew(address)'], + '0x87914c6f': ['prolongateContract()'], + '0x9801cb8e': ['ProofOfExistence()'], + '0x4671e65e': ['proposeEmergencyWithdrawal(address)'], + '0xac4e73f9': ['proposeReverse(string,address)'], + '0x1fdf6e0c': ['protectKingdom()'], + '0xa9b8f7b8': ['ProtectTheCastle()'], + '0x4f09eba7': ['proxyApprove(address,uint256,bytes32)'], + '0xe82b7cb2': ['proxySetCosignerAddress(address,bytes32)'], + '0xea98e540': [ + 'proxyTransferFromToICAPWithReference(address,bytes32,uint256,string)' + ], + '0xf0cbe059': [ + 'proxyTransferFromWithReference(address,address,uint256,bytes32,string)' + ], + '0xc5487661': ['proxyTransferToICAPWithReference(bytes32,uint256,string)'], + '0x64ef212e': ['proxyTransferWithReference(address,uint256,bytes32,string)'], + '0xd94073d4': ['PT()'], + '0x8940aebe': ['publicKey(uint256)'], + '0x8b2e6dcf': ['publish(bytes32)'], + '0x57e25a79': ['PullPaymentCapable()'], + '0x0eb495c2': ['pushCity()'], + '0x4616caa9': ['pushCoin(uint256,address,string)'], + '0xacc8cb18': ['pushTerm(string)'], + '0xafd09bab': ['quadrupler()'], + '0x4306cc3f': ['queryEarnings(address)'], + '0x83eed3d5': ['queryN(uint256,string,bytes)'], + '0xc55c1cb6': ['queryN_withGasLimit(uint256,string,bytes,uint256)'], + '0xfdd3a879': ['quick()'], + '0xf28a7912': ['quick2()'], + '0xe0c7c117': ['Randao()'], + '0x0b15650b': ['randInt(uint256,uint256)'], + '0x8e3957d9': ['RandomNumber()'], + '0x7741b4ec': ['RandomNumberFromSeed(uint256)'], + '0xb863bd37': ['random(uint256)'], + '0xeb7cdb56': ['rankDown(uint256,uint256)'], + '0x74fbbc86': ['rate(uint256,uint256,string)'], + '0xba344743': ['_rawTransfer(address,address,uint256)'], + '0x2d2800f1': ['react()'], + '0xb7213bd4': ['readLog(uint256)'], + '0x7d7c2a1c': ['rebalance()'], + '0x248582b0': ['receivePaymentForGoodsSoldEarly()'], + '0x743e0c9b': ['receiveTokens(uint256)'], + '0x49d55d9d': ['receiveTransfer(uint256)'], + '0xc864e760': ['recordCommissionEarned(uint256)'], + '0xe51ace16': ['record(string)'], + '0xf06d335e': ['_recoverAccount(address,address)'], + '0x648bf774': ['recover(address,address)'], + '0x0cd865ec': ['recover(address)'], + '0x0ca35682': ['recover(uint256)'], + '0xf32efd3c': ['recoverUser(address,address,uint256,uint8,bytes32,bytes32)'], + '0xe20bbd8d': ['RecoveryWithTenant()'], + '0x0f23cbaa': ['recycle()'], + '0x578bcc20': ['reduceDebt(address,address,uint256)'], + '0x538e0759': ['refill()'], + '0x58b1f29c': ['refundBounty(uint256)'], + '0x847f8a10': ['Refund(uint32)'], + '0x5af36e3e': ['refund(uint256,uint256)'], + '0x66b42dcb': ['register(address,string,uint256,string)'], + '0xeeda149c': ['Register(address)'], + '0x4420e486': ['register(address)'], + '0x8d59cc02': ['register(address,string,string)'], + '0x8b7f0ddd': [ + 'register(address,address,string,string,bytes32[],uint256,string)' + ], + '0x7b1a547c': ['registerAs(address,string,uint256,string,address)'], + '0x3facd57c': [ + 'registerBill(uint256,address,address,uint256,uint256,uint256)' + ], + '0x84c344fe': ['_register(bytes4,string)'], + '0xb0fd935b': ['registerCertificationDb(address)'], + '0x4cd995da': ['registerCompany(address,string)'], + '0x669ee827': ['RegisterDevice()'], + '0xfe63300a': [ + 'registerExternalBill(uint256,address,address,uint256,uint256,uint256)' + ], + '0x68af4971': ['registerListening()'], + '0x00e7d289': ['registerListening(address)'], + '0x7f6d8955': ['RegisterOne(uint32,address,address)'], + '0xf2c298be': ['register(string)'], + '0x3ffbd47f': ['register(string,string)'], + '0xaeb4f0d3': ['RegisterTwo(address,address)'], + '0x8ae986cf': ['registrantApprove(address)'], + '0xe9fe799e': ['registrantRemove(address)'], + '0x7db9743b': ['Registry()'], + '0x6d15f208': ['reject(string,uint256,uint16,address,uint256)'], + '0xc76a4bfb': ['relayReceiveApproval(address,address,uint256,bytes)'], + '0xd67cbec9': ['release(uint32,uint32,uint32,bytes20)'], + '0xa7b2d4cb': ['remove(int256,address)'], + '0xf3ee6305': ['removeCertificationDocument(address,bytes32)'], + '0x9c30936f': ['removeCertificationDocumentFromSelf(bytes32)'], + '0xba4c206e': ['removeCertificationDocumentInternal(address,bytes32)'], + '0x0066753e': ['removeCertifier(address)'], + '0xd5df7559': ['removeDocument(uint256)'], + '0xac18de43': ['removeManager(address)'], + '0xba7dc45f': ['_removeOperation(bytes32)'], + '0x2c4cb4be': ['removeRegistryFromNameIndex(address)'], + '0x669459a7': ['removeRegistryFromOwnerIndex(address)'], + '0xaf55bba0': ['removeRegistryFromTagsIndex(address)'], + '0xf25eb5c1': ['removeReverse()'], + '0x80599e4b': ['remove(string)'], + '0x7e32a592': ['repairTheCastle()'], + '0x631de4d6': ['replace(address,address)'], + '0x9fd4f7d1': ['replaceWizard(address)'], + '0xce87f626': ['replaceWizardRP(address)'], + '0xeaa1f9fe': ['reqisterListening(address)'], + '0x27f06fff': ['requestFillUp(uint256)'], + '0x2e5d1042': ['requestPayout(uint256,uint256,bytes32,uint256,uint256)'], + '0xe9c63b9c': ['requestPeerBalance()'], + '0x4c9ed763': ['requestTokensBack()'], + '0x0ac28725': ['requestTradeDeal(uint256,uint256,string)'], + '0xf802075f': ['requiredEndowment()'], + '0x432ced04': ['reserve(bytes32)'], + '0x92698814': ['reserved(bytes32)'], + '0x6676871d': ['reserved_funds()'], + '0x6423db34': ['Reset()'], + '0x478e25bf': ['resetAction(bytes32)'], + '0x769796fe': ['resetAction(uint256)'], + '0xb181a8fc': ['resetContract()'], + '0xf50d3914': ['resetFoundationtList()'], + '0xd337616e': ['resetLottery()'], + '0x5cfd8c24': ['ResetPonzi()'], + '0x433d4aab': ['resolve(uint8,uint8)'], + '0xa6403636': ['resolve(uint8,bytes32,bytes32,bytes32)'], + '0x1ef3755d': ['restart()'], + '0xa987d654': ['restoreItem(uint256)'], + '0xc4bc5da5': ['resumeContract()'], + '0x61b20d8c': ['retrieveFunds()'], + '0x85c78fac': ['retryOraclizeRequest(uint256)'], + '0x5cbc85d0': ['returnBounty(uint256)'], + '0xcff2fa42': ['_returnFee(address,uint256)'], + '0x0ca7395f': ['returnFund(address,uint256)'], + '0xec81e22e': ['returnmoneycreator(uint8,uint256)'], + '0x7ac4b05e': ['returnMyMoney(uint256)'], + '0x9ec35352': ['returnRandom()'], + '0xebaf7f2f': ['returnReward(uint256)'], + '0x66d8c463': ['reveal(bytes32,string)'], + '0x32d5fe98': ['revealCampaign(uint256,uint256)'], + '0x9348cef7': ['reveal(uint256,uint256)'], + '0x84ad6ff3': ['ReversibleDemo()'], + '0x05f8b6f5': ['_rewireIdentities(bytes32[],uint256,uint256,uint32)'], + '0x8390b02a': ['rfindPtr(uint256,uint256,uint256,uint256)'], + '0xe1108706': ['rfind()'], + '0xf7149220': ['RNG()'], + '0x4e1053cc': ['RobinHoodPonzi()'], + '0xd2602930': ['RockPaperScissors()'], + '0x8d216186': ['roll(uint256,bytes32)'], + '0x5a7a8850': ['rollWithSeed(bytes32)'], + '0xb73405a9': ['roundMoneyDownNicely(uint256)'], + '0x5ccc3eaa': ['roundMoneyUpToWholeFinney(uint256)'], + '0x96d02099': ['rsplit()'], + '0xdd727ea6': ['runJackpot()'], + '0x5674a3ed': ['runLottery()'], + '0x4d366398': ['runPeerBalance()'], + '0x677cee54': ['SafeConditionalHFTransfer()'], + '0x2baf4f22': ['_safeFalse()'], + '0x4401a6e4': ['safeSend(address)'], + '0x4269d8ef': ['_safeSend(address,uint256)'], + '0xa97ffd5e': ['safeToSell(uint256)'], + '0x38e48f06': ['save(string)'], + '0x3fb27b85': ['seal()'], + '0xddbbc35c': ['searchByName(string)'], + '0x42cf0e72': ['searchByOwner(address)'], + '0xc82aac47': ['searchByTag(bytes32)'], + '0x40a49a96': ['searchSmallestInvestor()'], + '0xf7c2b38c': ['seconds_left()'], + '0xcf1cd249': ['secureSend(address)'], + '0x85e5bb3a': ['Security_AddPasswordSha3HashToBankAccount(bytes32)'], + '0x7d94792a': ['seed()'], + '0xe4cc1161': ['seedWithGasLimit(uint256)'], + '0x88b9e10e': ['seizeTokens(address,uint256)'], + '0x6be505f5': ['selectWinner(bytes32)'], + '0x9cb8a26a': ['selfDestruct()'], + '0x2aa3177a': ['self_store()'], + '0x514dcfe3': ['seller_accept()'], + '0x2d592a34': ['sellKissBTC(uint256)'], + '0x41524433': ['sellKissBTCWithCallback(uint256,address,uint256)'], + '0xddb5b3ac': ['SellTokens()'], + '0xe4849b32': ['sell(uint256)'], + '0x227185d6': ['Send1Get2()'], + '0xd6006e88': ['send(address[],uint256[],uint256)'], + '0x3e58c58c': ['send(address)'], + '0x35d13969': ['SendAllMoney()'], + '0x3d21aa42': ['sendApproval(address,uint256,address)'], + '0xd1e15045': ['sendBack()'], + '0x5292af1f': ['sendBalance(address)'], + '0xeb455dc6': ['sendBitcoin(string,uint256)'], + '0xb938bf42': ['sendBounty(bytes32)'], + '0x9894221a': ['SendCashForHardwareReturn()'], + '0x010731c0': ['sendCryptedHand(bytes32)'], + '0x78ec81a0': ['sendEarnings(address)'], + '0xb1d05422': ['SendEmail(string,string)'], + '0xbb6b4619': ['SendETC(address)'], + '0x3a314b24': ['SendETH(address)'], + '0x9c6034a7': ['sendIfNotForked()'], + '0x7b02b2c9': ['sendMsg(address,string)'], + '0x76d438b0': ['sendReward(uint256,uint256)'], + '0xbf8fc670': ['sendToAggregation(uint256)'], + '0x6620a935': ['sendToOwner()'], + '0x03750d94': ['serverSeed(address,bytes32)'], + '0x7eff1465': ['setAccountAllowance(address,address,uint256)'], + '0x5e03d393': ['setAccountFrozenStatus(address,bool)'], + '0xf6d339e4': ['setAddress(bytes32,string,address)'], + '0x3c84f868': ['set(int256,address,uint256)'], + '0x213b9eb8': ['setAddr(string,address)'], + '0x5d96ec65': ['setAdministrator(address,string,bool)'], + '0xf8af9e6f': ['setAdv(uint256,string,string)'], + '0x058d7433': ['setAlliesContract(address)'], + '0x7a837213': ['setAllowedAccount(address)'], + '0xf8ec4bf2': ['setAllowTransactions(bool)'], + '0x7948f523': ['setAmbiAddress(address,bytes32)'], + '0x9fa5e5d5': ['setARKowner(address)'], + '0xd0d552dd': ['setAsset(address)'], + '0x9f203255': ['setAuditor(address)'], + '0xda7fc24f': ['setBackend(address)'], + '0x754dea40': ['setBackendOwner(address)'], + '0x5c89c10d': ['setBannedCycles(uint256[])'], + '0x1c31f710': ['setBeneficiary(address)'], + '0xcf09e6e1': ['SetBigContract(address)'], + '0xc1441172': ['setBlackFlagRequest(uint256,uint256)'], + '0x2ffda1e0': ['setBlackflag(uint256,bool)'], + '0x6b5caec4': ['setBot(address)'], + '0x23e9c216': ['setBounty(address,string,uint256)'], + '0x16ce8a69': ['setBuilding(uint256,uint256)'], + '0x47448e8a': ['set(bytes32,string,bytes32)'], + '0x37881810': ['setCallbackAddress(address)'], + '0x8702735c': ['setCapitol(uint256,uint256)'], + '0x951b01c5': ['setCertifierDb(address)'], + '0xeef8e35f': ['setChainyURL(string)'], + '0xf8bd526e': ['setCoinageContract(address)'], + '0xa510f776': ['setCompany()'], + '0x4c2d71b3': ['setConfigAddress(bytes32,address)'], + '0x1e0c7ed4': ['setConfigBool(bytes32,bool)'], + '0xe8a5282d': ['setConfig(bytes32)'], + '0x810a882f': ['setConfigBytes(bytes32,bytes32)'], + '0x3e8f5b90': ['setConfig(string,uint256)'], + '0xbc45d789': ['setConfigUint(int256,bytes32,uint256)'], + '0xfd6f5430': ['setContent(string,bytes32)'], + '0x92eefe9b': ['setController(address)'], + '0x5e6ad49d': ['_setCosignerAddress(address)'], + '0x82fc49b8': ['setCosignerAddress(address)'], + '0x986dcd4d': ['setCycleLimit(uint256)'], + '0xe73a914c': ['setDAO(address)'], + '0xc52bd836': ['setDappOwner(bytes32,address)'], + '0x03959bb7': ['setDataContract(address)'], + '0x4a994eef': ['setDelegate(address,bool)'], + '0x90c3f38f': ['setDescription(string)'], + '0x172d8a30': ['setDirectorLock(uint256,uint256)'], + '0xa1b7ae62': ['setdirectorName(string)'], + '0x38eaf913': ['setDirectorNode(string)'], + '0x423e1298': ['setDoNotAutoRefundTo(bool)'], + '0x6716a692': ['setDVIP(address)'], + '0x74331be7': ['sete(address)'], + '0xb56e1bca': ['setExchangeToken()'], + '0xfe4a3ac9': ['setExecPrice(uint256)'], + '0x01cceb38': ['setExpiry(uint256)'], + '0xb35893f3': ['setExporter()'], + '0x87cc1e1c': ['setExporterBank()'], + '0xa4502cb8': ['setExportFee(address,uint256)'], + '0xe5782fd5': ['setFeeStructure(uint256,uint256,uint256)'], + '0x69fe0e2d': ['setFee(uint256)'], + '0x02aa274b': ['setForward(bytes4,address)'], + '0x69569a51': ['setFrontend(address)'], + '0x576eac66': ['setFundingGoal(uint256)'], + '0x711953ef': ['setGameAddress(address)'], + '0x2187a833': ['setGreenToken()'], + '0x78f0161a': ['setGreyGreenPrice(uint8)'], + '0xad9ec17e': ['setGreyToken()'], + '0xd148288f': ['setHoldingPeriod(uint256)'], + '0xa37fd390': ['setHomeAdv(uint256,string)'], + '0x9fb755d7': ['setHotWallet(address)'], + '0x0a3b1cd2': ['setHotwallet(address)'], + '0x1bd9c46e': ['setImporter()'], + '0xae2df7b3': ['setImporterBank()'], + '0xe2c61114': ['setImportFee(address,uint256)'], + '0xa8659216': ['setInitialLockinDays(uint256)'], + '0x26b916b4': ['Set_Interest_Rate(uint256)'], + '0x9fcbc738': ['setIntermediate(address)'], + '0x18f303a1': ['SetInternalValues(uint8,uint256)'], + '0x7f0c949c': ['setJurisdication(string)'], + '0x74f519db': ['setLastTimestamp(uint256,uint256)'], + '0x27ea6f2b': ['setLimit(uint256)'], + '0x9cb31079': ['setLowLimit(uint256)'], + '0x73ffd969': ['setMap(uint256,uint256,uint256)'], + '0x457dd8b3': ['setMasterKey(address)'], + '0x5e404de3': ['setMaximumCredit(uint256)'], + '0xee8ff562': ['setMaxProfit()'], + '0x3b91ceef': ['setMax(uint256,uint256)'], + '0x1ca60aeb': ['setMeltingContract(address)'], + '0x50944a8f': ['setMembership(address)'], + '0x91cd242d': ['setMeta(bytes32,bytes32,bytes32)'], + '0xdd93890b': ['setMeta(uint256,bytes32,bytes32)'], + '0x35930e13': ['setMinimalRewardedBalance(uint256)'], + '0xb0414a2d': ['setMinimumGasLimit(uint256)'], + '0x03251a08': ['setMin(uint256,uint256)'], + '0xb1662d58': ['setModule(address,bool)'], + '0x29de91db': ['setMsg(address,uint256)'], + '0x8aa33776': ['setMsgPrice(uint256)'], + '0x5ac801fe': ['setName(bytes32)'], + '0xfe55932a': ['setName(uint256,string)'], + '0x4b3b6168': ['SetNewBigContract(address)'], + '0xc4d9102f': ['setNextID(uint256,int256)'], + '0xfc9e53df': ['setNextRegistrar(address)'], + '0x8389f353': ['setNumCities(uint256)'], + '0x8173b813': ['setNumCities(uint256,uint256)'], + '0x755b5b75': ['setNumUnits(uint256,uint256)'], + '0x65228934': [ + 'setOperationsCallGas(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)' + ], + '0x7adbf973': ['setOracle(address)'], + '0xc7e22ac4': ['setOracleGas(uint256)'], + '0x89ed0b30': ['setOraclizeGas(uint32)'], + '0x18f3fae1': ['setOversight(address)'], + '0xd62b255b': ['setOwner(address,string)'], + '0x167d3e9c': ['SetOwner(address)'], + '0x7acbfb65': ['setOwner(uint256,uint256)'], + '0xffe302d1': ['setPlz(string)'], + '0x2e3be78d': ['setPrecisionDirect(uint8)'], + '0x3f9f5b68': ['setPreviousID(uint256,int256)'], + '0x36f7cd70': ['setPricePerStake(uint256)'], + '0x5e983d08': ['setPrices()'], + '0x05fefda7': ['setPrices(uint256,uint256)'], + '0xf7d97577': ['setPrice(uint256,uint256)'], + '0x53d97e65': ['setPrizes(uint32[])'], + '0x6e0d98fe': ['setProbabilities(uint32[])'], + '0x7137ed47': ['setProxyContract(address)'], + '0x8e25071a': ['setProxyCurrator(address)'], + '0xc24924d6': ['setQueryFee(uint256)'], + '0xe50d0473': ['SetRank(uint8,address,uint16)'], + '0x50b7b7a2': ['setRating(bytes32,uint256)'], + '0x50f07cf9': ['setReadingDelay(uint256)'], + '0x8279c7db': ['setReceiverAddress(address)'], + '0xa0a2f629': ['setReferralId(uint256,address)'], + '0xe0117441': ['setRegistrationPrice(uint256)'], + '0x718bd6dd': ['setRequestUntil(uint8)'], + '0xaf030d2c': ['setResult(uint256,uint256,bytes32)'], + '0x0381cb3b': ['setRowcol(uint256,uint256[2])'], + '0xe1a9109d': ['setSeedPrice(uint256)'], + '0x09d2d0b9': ['setServiceAccount(address,bool)'], + '0xa8026912': ['setSource(address)'], + '0x81183633': ['setStandard(bytes32)'], + '0x3e0a322d': ['setStartTime(uint256)'], + '0x49e65440': ['setSymbol(bytes32)'], + '0xb1233451': ['setTerm(uint256,string)'], + '0xb950556a': ['setThingValid(bytes32[],bool)'], + '0xce592586': ['setThresold(uint256,uint256)'], + '0xaee84f6b': ['setTime(address,uint256)'], + '0x9a9c29f6': ['settle(uint256,uint256)'], + '0xb33a8a11': ['setTokenReference(address)'], + '0x55db4092': ['setTOS(address,bool)'], + '0x506e106c': ['setToS(string)'], + '0xf7ea7a3d': ['setTotalSupply(uint256)'], + '0xa33dd801': ['setTreasuryBalance(uint256)'], + '0x4dc43eaf': ['setTreasury(uint256,uint256)'], + '0xdd57d5c5': ['setTrust(address)'], + '0xacb6c69b': ['setTrustedClient(address)'], + '0x1d7b5baf': ['setUint(int256,bytes32,string,uint256)'], + '0x2f30c6f6': ['set(uint256,address)'], + '0x468129a5': ['setUnit(uint256,uint256,uint256)'], + '0x7bc0ff20': ['setupExportFee(address,uint256)'], + '0x26881518': ['setupFee(address)'], + '0x92d8c8cf': ['setupImportFee(address,uint256)'], + '0x294f3d4d': ['setUpLimit(uint256)'], + '0xce8d054e': ['_setupNoCallback()'], + '0x12ab7242': ['setupStackDepthLib(address)'], + '0x1d124fe4': ['setUtils2(address)'], + '0x69953501': ['setUtils(address)'], + '0x4bc2a657': ['setVoter(address)'], + '0x7318b453': ['setVotetUntil(uint8)'], + '0x4173b181': ['setWeiPrice(uint256)'], + '0x0df71602': ['setWinner(uint256)'], + '0x12819817': ['setXauForGasCurrator(address)'], + '0xef4bdfdd': ['Set_your_game_number_between_1_15(string)'], + '0xb3ade772': ['shipProducts(string,string)'], + '0x83d852d9': ['shutdownTransactions()'], + '0x95d5a1be': ['SignatureReg()'], + '0x76cd7cbc': ['sign(bytes)'], + '0x5f68804e': ['SimpleLotto()'], + '0x152fb125': ['SimpleMixer()'], + '0x4ac7becf': ['SimpleSign()'], + '0xc83be888': ['single_move(uint256,uint8,uint8)'], + '0x70d084c0': ['SingularDTVCrowdfunding()'], + '0x0ab58ead': ['SingularDTVFund()'], + '0x0b590c6b': ['SingularDTVToken()'], + '0x1ff13086': ['size(int256)'], + '0x9c4baf27': ['Skywalker(address,address)'], + '0x1a88bc66': ['slot()'], + '0x853552d7': ['_slotAddNew(address)'], + '0xee564544': ['_slotCancelNew()'], + '0x16f9ce49': ['_slotCommitNew(address)'], + '0x6fe665e9': ['SlotMachine()'], + '0x22593300': ['Small(address)'], + '0x5503a659': ['smallponzi()'], + '0xe3b26a8c': ['SocialNetwork()'], + '0x5d0be9de': ['softWithdrawRevenueFor(address)'], + '0xd5dbb1ad': ['solveBet(address,uint8,bool,uint8,bytes32,bytes32)'], + '0xb2f2588b': ['sortNumbers(uint8[3])'], + '0xface030b': ['SpinTheWheel(address)'], + '0x56fa47f0': ['split(address)'], + '0x0f2c9329': ['split(address,address)'], + '0x9c709343': ['split(bool,address)'], + '0xf7654176': ['split()'], + '0xd9d2d058': ['Splitter()'], + '0x2672b3e2': ['SplitterEtcToEth()'], + '0x8946d33f': ['SplitterEthToEtc()'], + '0xb7266456': ['StandardToken()'], + '0x70983e91': ['startBoardProposal(uint256,address)'], + '0x9f35d3b2': ['start(string,string,uint256,uint256,uint256,uint256)'], + '0x0fbf7151': ['startsWith()'], + '0xa1cb31b7': ['_state()'], + '0x12253a6c': ['stopContract()'], + '0x975057e7': ['store()'], + '0xdda9939c': ['Store(address[])'], + '0x877653f0': ['_storeBalanceRecord(address)'], + '0xf60381a1': ['stra2cbor(string[])'], + '0x2fcb6628': ['_stringGas(string,string)'], + '0xfc01abbe': ['stringToBytes32(string,string)'], + '0x9077dcfd': ['submitCoding(string,uint256)'], + '0x2da8f764': ['submitVideo(string,string)'], + '0xb71c47a2': ['surrender()'], + '0xcd57a448': ['SwapContract(address,uint256)'], + '0x6b76484e': ['swap(address,address)'], + '0xd60dcb5d': ['Switch()'], + '0xb660d77c': ['switchMPO(address,address)'], + '0xd422e4e0': ['takeFee(address,uint256,string)'], + '0x4f073130': ['takeOrder(bool,uint256,uint256)'], + '0xbf55486b': ['Tanya()'], + '0xe2ee9941': ['tap(bytes20)'], + '0x420ef2b3': ['TargetHash()'], + '0x922fc84b': ['taskProcessedNoCosting(uint256)'], + '0x36e6b92e': ['taskProcessedWithCosting(uint256,uint256)'], + '0x93cc9162': ['taskRejected(uint256,uint256)'], + '0x4dc7cc55': ['terminateAlt()'], + '0x08714bfa': ['TestContract()'], + '0x1465aa97': ['testingContract()'], + '0x2af7ceff': ['testPrice(uint256)'], + '0xbab86ea8': ['test(string,string)'], + '0x4cad42d3': ['testWager()'], + '0xc96593a0': ['The10ETHPyramid()'], + '0x83d8a90f': ['theDonkeyKing()'], + '0x87fd0421': ['TheEthereumLottery()'], + '0x0e3f732a': ['TheGame()'], + '0xafbec8df': ['TheGrid()'], + '0x7399646a': ['theRun()'], + '0x83c51a38': ['thesimplegame()'], + '0x6f9a023c': ['theultimatepyramid()'], + '0x3c6e03d7': ['thewhalegame()'], + '0x18489f50': ['thingExist(bytes32[])'], + '0xe3848e5b': ['thing(string,string,string)'], + '0xda25c0cd': ['ThisExternalAssembly()'], + '0x857d4c07': ['throwScraps(uint256)'], + '0x18253234': ['ticketsAvailable()'], + '0xd7f746ce': ['tickingBomb()'], + '0x5f17114e': ['TimeDeposit()'], + '0x2f5a5c5b': ['timegame()'], + '0xcfed9199': ['timePassed(uint256)'], + '0xdd137b5d': ['toBase58(uint256,uint8)'], + '0xb05e390a': ['TokenEther(string,string)'], + '0x7ff9b596': ['tokenPrice()'], + '0x31380c89': ['TokenSale()'], + '0x4da47ba0': ['TokenSale(address,uint256)'], + '0xd5089396': ['Token(string,string,uint8,uint256)'], + '0x6c1a5b8c': ['TOKEN_TARGET()'], + '0xb29c2493': ['token(uint256,string,uint8,string)'], + '0xf2022905': ['toldYouItWouldWork()'], + '0x283a4576': ['Tomeka()'], + '0x51560da9': ['topDogInfo()'], + '0x43ec3f38': ['toSliceB32(bytes32)'], + '0xafed762b': ['toSlice(string)'], + '0x15a03930': ['TossMyCoin()'], + '0x47e46806': ['toString()'], + '0xfc7b9c18': ['totalDebt()'], + '0x1ff517ff': ['totalDebt(address)'], + '0x7fef036e': ['totalEntries()'], + '0x5216aeec': ['totalInvested()'], + '0xdc19266f': ['Total_of_Players()'], + '0x6831c169': ['totalPayedOut()'], + '0x6a8c2437': ['totalRescues()'], + '0xb524abcf': ['totalSupply(bytes32)'], + '0xbff1f9e1': ['totalUsers()'], + '0x8caaaae6': ['totalWeiPrice()'], + '0x637e86eb': ['totBOTs()'], + '0xbb39a960': ['trade(address,uint256,address,uint256)'], + '0x04bb754c': ['TradeFinancing()'], + '0x4847a79c': ['_transfer(address,uint256)'], + '0x57cfeeee': ['transfer(address,uint256,bytes32)'], + '0xdeb80111': ['transfer_asset(address,uint256)'], + '0x22e803c2': ['transferBounty()'], + '0x60063887': ['transferDebt(address,address,address,uint256)'], + '0xddd41ef6': ['transferDirector(address)'], + '0x30e0789e': ['_transfer(address,address,uint256)'], + '0x63334c58': ['transferETC(address)'], + '0xd50f6bf0': ['transferETH(address)'], + '0x97fcb54e': ['transfer_eth(address,uint256)'], + '0xa0eda9f2': ['_transferFee(address,uint256,string)'], + '0xcb712535': ['_transferFrom(address,address,uint256)'], + '0xc204f9f1': ['_transferFromToICAP(address,bytes32,uint256)'], + '0xa525f42c': ['transferFromToICAP(address,bytes32,uint256)'], + '0xcac77df7': [ + '__transferFromToICAPWithReference(address,bytes32,uint256,string)' + ], + '0x0b1e400a': [ + '_transferFromToICAPWithReference(address,bytes32,uint256,string)' + ], + '0xa48a663c': [ + 'transferFromToICAPWithReference(address,bytes32,uint256,string)' + ], + '0x48a490fb': ['transferFromTreasury(address,uint256)'], + '0xcacc24eb': ['transferFromViaProxy(address,address,address,uint256)'], + '0x31c6c4cf': [ + 'transferFromWithReference(address,address,uint256,bytes32,string)' + ], + '0x3de9e4c6': ['__transferFromWithReference(address,address,uint256,string)'], + '0xa10bee85': ['_transferFromWithReference(address,address,uint256,string)'], + '0x6461fe39': ['transferFromWithReference(address,address,uint256,string)'], + '0x752a3df6': ['transferIfHardForked(address)'], + '0xd6a619e3': ['transferIfPuritanical(address)'], + '0x29605e77': ['transferOperator(address)'], + '0x235c002d': ['transferOther(address,address,uint256)'], + '0x67af26fb': ['transferOtherFrom(address,address,address,uint256)'], + '0x1301ee02': ['transferringETC(address)'], + '0xd4245e5b': ['transferringETH(address)'], + '0xfbf58b3e': ['transfer(string,address)'], + '0xd3aa22c7': ['transferTLA(string,address)'], + '0xa25057de': ['_transferToICAP(bytes32,uint256)'], + '0x733480b7': ['transferToICAP(bytes32,uint256)'], + '0x3bf2313d': ['__transferToICAPWithReference(bytes32,uint256,string)'], + '0x078c3fa4': ['_transferToICAPWithReference(bytes32,uint256,string)'], + '0x77fe38a4': ['transferToICAPWithReference(bytes32,uint256,string)'], + '0xe7dafdb6': ['transfer_token(address,address,uint256)'], + '0x12514bba': ['transfer(uint256)'], + '0x240ecad5': ['transferViaProxy(address,address,uint256)'], + '0x6d16f79c': ['__transferWithReference(address,uint256,string)'], + '0x51b3d7b9': ['_transferWithReference(address,uint256,string)'], + '0xac35caee': ['transferWithReference(address,uint256,string)'], + '0x1d065dde': ['_transferWithReward(address,address,uint256)'], + '0xe99543aa': ['Trash(uint256)'], + '0x8fe58eb9': ['Triger()'], + '0x54204ad4': ['triple()'], + '0x432c685f': ['trustClient(address)'], + '0x464f37c9': ['trustedChildRefund()'], + '0x866f6736': ['trustedChildWithdraw()'], + '0x2e6e504a': ['trusteeWithdraw()'], + '0x65343fcb': ['TrustEth()'], + '0x5fdf05d7': ['two()'], + '0x0d0c2008': ['TwoAndAHalfPonzi()'], + '0x49cc954b': ['twoYearsPassed()'], + '0x4dd850fb': ['UfoPonzi()'], + '0xf76f950e': ['uint2str(uint256)'], + '0x9e1e6528': ['uncertify(address)'], + '0x734d8287': ['unclaimedFees()'], + '0xf0d474f9': ['underdogCount()'], + '0x6eb7b4c2': ['underdogInfo(uint256)'], + '0x75f40f40': ['underdogPayoutFund()'], + '0x2880ebe7': ['underdogPayoutMarkup()'], + '0xcb3e64fd': ['unhalt()'], + '0xff81fb91': ['unhint(int256,bytes32)'], + '0xd4859dbc': [ + 'UniversalFunctionSecure(uint8,bytes32,bytes32,bytes32,bytes32,bytes32)' + ], + '0x579badf6': [ + 'UniversalFunction(uint8,bytes32,bytes32,bytes32,bytes32,bytes32)' + ], + '0x2ec2c246': ['unregister(address)'], + '0x1a0919dc': ['unregister(bytes32)'], + '0x4e116eb8': ['unRegisterCertificationDb(address)'], + '0xf1a00a53': ['unregisterListening(address)'], + '0xf295206f': ['_unsafeSend(address,uint256)'], + '0x9447fd0a': ['until()'], + '0x63def590': ['untrustClient(address)'], + '0x6a4b6aa5': ['untrustedChildWithdraw()'], + '0x0e38901a': ['unvault(uint256)'], + '0xe0b1cccb': ['updateBalance(address,uint256)'], + '0xfd8055d2': [ + 'updateBOTBillingInfo(uint256,string,address,string,string,uint256)' + ], + '0xb4a5ef58': ['updateDefaultTimeoutPeriod(uint256)'], + '0x2ffb9e64': ['updateGasForXaurData(uint256,uint256)'], + '0x4f10acc1': ['updateGoldFeeData(uint256)'], + '0x7c582304': ['updateInvestmentTotal(address,uint256)'], + '0xf2016a4f': ['updateMinEthPerNotification(uint256)'], + '0x10f41715': ['updateMintingData(uint256,uint256)'], + '0xb3485dca': ['UpdatePrice(uint8,uint32)'], + '0x482961e1': ['updateReading(uint256,uint256)'], + '0x9dc35799': ['updateReading(uint256)'], + '0x71e11354': ['updateRegistration(string,string)'], + '0x645dce72': ['updateRelease(uint32,uint32,uint32,bytes20,bool)'], + '0x5dddea66': ['updateState(uint256,uint8,uint256)'], + '0xbc058968': ['updateThingData(bytes32[],bytes32[],uint88)'], + '0x4ca7fbd0': ['updateTokenPriceWeekTwo()'], + '0x1d4b0796': ['updateTxStats()'], + '0x5a6c787e': ['updateWithMPO()'], + '0x1aa86370': ['updateXIPFSPublicKey(string)'], + '0xac7ffae3': ['updt(uint256,string,uint256,uint256,string,string,address)'], + '0x0900f010': ['upgrade(address)'], + '0xf597a499': ['UserDatabase(uint256)'], + '0x376fe102': ['userId(address)'], + '0xe6b972f5': ['userName(address)'], + '0x7b12df39': ['userProfits()'], + '0xe28fed1e': ['userRescues(address)'], + '0x8a65d874': ['userStats(address)'], + '0xed498fa8': ['userTokens(address)'], + '0xccf1ab9b': ['usurpation()'], + '0x83f6d9a4': ['validateNameInternal(string)'], + '0xb8d4efb5': ['validate_percent(uint8)'], + '0x67fc1c6a': ['validateProposedMonarchName(string)'], + '0xd22c391a': [ + 'validateProposedThroneRules(uint256,uint256,uint256,uint256,uint256)' + ], + '0x8f7fe231': ['ValidetherOracle()'], + '0xc0a239e3': ['valuePerShare()'], + '0xcc189d00': ['Vault(address,uint256)'], + '0xe820a32f': ['vetoPayout(uint256,uint256)'], + '0x4228974c': ['Videos()'], + '0x226685ee': ['Visit()'], + '0x6bf52ffa': ['Vote()'], + '0x5f09952e': ['voteAllowTransactions(bool)'], + '0x52a554a1': ['voteBoardProposal(uint256,address,bool)'], + '0x187a62d5': ['voteEmergencyWithdrawal(bool)'], + '0x045c6ce0': ['voteForProposal(uint256)'], + '0x58ae8bcf': ['voteInMasterKey(address)'], + '0x901d7775': ['voteOutMasterKey(address)'], + '0x23637e60': ['votePrice(uint256,bool)'], + '0x76e4ca0d': ['voteQuorum(uint256,bool)'], + '0xf2561a43': ['voteSuicide(address)'], + '0x0bf75567': ['voteSuperQuorum(uint256,bool)'], + '0xb3f98adc': ['vote(uint8)'], + '0xe2cdd42a': ['vote(uint256,address,bool)'], + '0x0121b93f': ['vote(uint256)'], + '0x655388be': ['walkTowardsBlock()'], + '0x5d5483b3': ['WatchAppliedFeePercentage()'], + '0xd628e0a6': ['WatchBalance()'], + '0xe0834ea4': ['WatchBalanceInEther()'], + '0x252786e4': ['WatchBlockSizeInEther()'], + '0xcf6b3822': ['WatchCollectedFeesInSzabo()'], + '0x82381c96': ['WatchCurrentMultiplier()'], + '0x20bfec70': ['WatchFees()'], + '0xc9734ebd': ['WatchLastPayout()'], + '0x61ba3377': ['WatchLastTime()'], + '0xfb34fc6f': ['WatchNextBlockReward()'], + '0x4ef5710a': ['WatchNumberOfPlayerInCurrentRound()'], + '0x6b3a87d2': ['WatchWinningPot()'], + '0xbe0638e4': ['WealthShare()'], + '0x05459f42': ['WeeklyLotteryB(address)'], + '0x836d6d66': ['WeeklyLotteryB(address,uint256)'], + '0x856f3080': ['WhatWasMyHash(bytes32)'], + '0x06e53f47': ['whichChainIsThis()'], + '0x9b19251a': ['whitelist(address)'], + '0xd6d02c51': ['whois(string)'], + '0x609ff1bd': ['winningProposal()'], + '0x95ceb4b3': ['winningProtocal()'], + '0x5ca3400c': ['WithBeneficiary(address)'], + '0x31e3e2fe': ['WithDraw()'], + '0x07bc6fad': ['withdraw(address,uint256,bytes32,uint256)'], + '0x8d92fdf3': ['withdrawAsset(uint256)'], + '0x5f52e9fd': ['WithdrawCashForHardwareReturn(uint256)'], + '0x1dd4914b': ['withdrawEtherOrThrow(uint256)'], + '0x24600fc3': ['withdrawFunds()'], + '0xf4aa1291': ['withdrawFundsAdvanced(address,uint256,uint256)'], + '0xceeafd9d': ['withdrawFundsAdvancedRP(address,uint256,uint256)'], + '0xc7f86c37': ['withdrawFundsRP()'], + '0x6103d70b': ['withdrawPayments()'], + '0x770c6cbb': ['WithDrawPreForkChildDAO()'], + '0x4f573cb2': ['withdrawRevenue()'], + '0xf108a7d2': ['withdraw(uint256,address,string)'], + '0x5b6b431d': ['Withdraw(uint256)'], + '0x44faa139': ['Withdraw(uint32)'], + '0xe63697c8': ['withdraw(uint256,address,uint256)'], + '0xf359671c': ['withdrawWithReference(address,uint256,string)'], + '0x89790192': ['WithFee(address,uint256)'], + '0x0d87a7c0': ['WLBDrawsDB()'], + '0xd08275f1': ['WolframAlpha()'], + '0x720c4798': ['workshop()'], + '0x214c9d50': ['WritedrawStatus()'], + '0xc0a1a949': ['x15()'], + '0x7266f4a4': ['X3()'], + '0xdb7ca38a': ['XaurmProxyContract()'], + '0x4f052648': ['XaurumDataContract()'], + '0xc1be4031': ['XaurumProxyERC20()'], + '0x71f297cc': ['XaurumToken(address)'], + '0x648621ec': ['xnotify(string)'], + '0xe3ceb06d': ['YesNo(bytes32,address,string,address,uint256)'], + '0xbc8f3bcb': ['ZeroDollarHomePage()'], + '0xbd02e4f6': ['calcRandomNumberAndGetPreliminaryGameResult(uint256,uint64)'], + '0x8f4fb958': ['calculateRandomNumberByBlockhash(uint256,address)'], + '0xae47a290': ['changeMaxBet(uint256)'], + '0x06394c9b': ['changeOperator(address)'], + '0x3aa5f4f7': ['changeTokenSettings(uint16,uint256,uint256)'], + '0x9a969768': ['distributeProfits(uint256)'], + '0x0f590c36': ['emergencyFixGameResult(uint64,uint256)'], + '0x364f4896': ['emission(address,address,uint256,uint16,uint16)'], + '0x7a8df1b9': ['getAffiliateInfo(address)'], + '0x9eb9dd3b': ['getBetsProcessed()'], + '0x2fd6d40b': ['getBetValueByGamble(uint8)'], + '0x6d12301c': ['getBetValue(bytes32,uint8)'], + '0x03ee8f08': ['getCoeff(uint16)'], + '0x38f77d69': ['getDistributeProfitsInfo()'], + '0xd02528e6': ['GetGameIndexesToProcess()'], + '0xb3fb14ad': ['getGameResult()'], + '0x49041903': ['getGame(uint64)'], + '0x824d5603': ['getIndex(uint16,uint16)'], + '0xf84f420b': ['getRandomNumber(address,uint256)'], + '0x267127ec': ['getTokenSettings()'], + '0x3cf885c4': ['isBitSet(uint256,uint8)'], + '0x15cff546': ['isOperationBlocked()'], + '0x257bcd6a': ['placeBet(uint256,bytes32,bytes32)'], + '0xfe73e3ec': ['preliminaryGameResult(uint64)'], + '0x89abeb19': ['ProcessGameExt(uint256)'], + '0x665bcc32': ['ProcessGames(uint256[],bool)'], + '0xa24d23eb': ['ProcessGame(uint256,uint256)'], + '0xaa677354': ['register(address,address)'], + '0xeb5904c0': ['setProfitDistributionContract(address)'], + '0x53c84526': ['setSmartAffiliateContract(address)'], + '0xf0caea2b': ['SmartRoulette()'], + '0xb599afc8': ['totalBetCount()'], + '0x4ce01d86': ['totalBetValue()'], + '0x2c4e591b': ['totalGames()'], + '0x37bdc99b': ['release(uint256)'], + '0x25fda176': ['notify(address,uint256)'], + '0x545e7c61': ['deploy(address,address)'], + '0xd3017193': ['addUser(address,uint256)'], + '0x2d580ef6': ['add(address,bytes32)'], + '0x79716e43': ['confirmTransaction(bytes32)'], + '0xca1d209d': ['fund(uint256)'], + '0x8b147245': ['update(bytes32)'], + '0x329ce29e': ['buyTile(uint256)'], + '0xa3908e1b': ['convert(uint256)'], + '0xdef2489b': ['convert(address)'], + '0x1e9a6950': ['redeem(address,uint256)'], + '0x74a93e6c': ['setTokenHolder(address,address)'], + '0xac940823': ['betOnLowHigh(bool)'], + '0x5521d17b': ['betOnColor(bool)'], + '0x338cdca1': ['request()'], + '0x59c87d70': ['request(bytes32)'], + '0x2bffc7ed': ['add(string,address)'], + '0x58d9fa04': ['addUser(uint256,address)'], + '0x64371977': ['set(uint256,string)'], + '0xf09ea2a6': ['offer(uint256,address,uint256,address)'], + '0x77fcb91d': ['forward(address,bool)'], + '0x53d9d910': ['create(address[],uint256,uint256)'], + '0xa8d95fb2': ['claim(address,string)'], + '0x591c515f': ['append(string,string)'], + '0xa7abc124': ['activate(bool,bool)'], + '0xc7f2e6af': ['Contribute(bytes20)'], + '0xebf6e91d': ['hit(uint256)'], + '0x7183616c': ['notarize(string)'], + '0x3da5c3ce': ['puzzle(address,bytes32)'], + '0x4b59e880': ['puzzle(address,bytes32,bytes32)'], + '0xae0a6b28': ['signature(string,bytes32)'], + '0x96b76c23': ['stand(uint256)'], + '0x6ea056a9': ['sweep(address,uint256)'], + '0x4637d827': ['trust(address)'], + '0x3af39c21': ['undefined()'], + '0x776d1a01': ['unvest(uint256,uint256,uint256,uint256,uint256,bool)'], + '0xb6608467': ['updateShares(uint256)'], + '0xf04da65b': ['getShares(address)'], + '0x90fa337d': ['storeBlockWithFeeAndRecipient(bytes,int256,int256)'], + '0x59d1d43c': ['text(bytes32,string)'], + '0x10f13a8c': ['setText(bytes32,string,string)'], + '0xa21174bb': ['DefaultReverseResolver(address)'], + '0x4e543b26': ['setResolver(address)'], + '0x0f5a5466': ['claimWithResolver(address,address)'], + '0xc0ee0b8a': ['tokenFallback(address,uint256,bytes)'], + '0x5a6b26ba': ['withdrawal(address,uint256)'], + '0x690e7c09': ['open(uint256)'], + '0x09fd018e': ['setClaimer(uint256,address,uint256)'], + '0x596c8976': ['close(uint256,uint256)'], + '0xdd0d74ff': ['IssueBank(address)'], + '0x228cb733': ['reward()'], + '0x99b721a5': ['rewardEthAnd(address[])'], + '0xeacccaf0': ['setReward(address,uint256)'], + '0x85eddeea': ['setReward(address[],uint256[])'], + '0xeb4dd8f2': ['confirm(address)'], + '0x342b7e71': ['setTokenList(address[])'], + '0xbd5dec98': ['withdraw(address[])'], + '0x640a4d0c': ['_deposited(address,address,uint256)'], + '0xc0b4fa6d': ['_reward(address[])'], + '0x18573bf9': ['calculeReward(uint256,uint256)'], + '0x73053f70': ['tokenDeposit(address)'], + '0x58e2cd76': ['watch(address)'], + '0xd9caed12': ['withdraw(address,address,uint256)'], + '0xb4427263': ['createTokens()'], + '0x01a7a8c0': ['batFundDeposit()'], + '0x229a4978': ['batFund()'], + '0x4172d080': ['tokenExchangeRate()'], + '0x6f7920fd': ['tokenCreationCap()'], + '0x8d4e4083': ['isFinalized()'], + '0x91b43d13': ['fundingEndBlock()'], + '0xa81c3bdf': ['ethFundDeposit()'], + '0xc039daf6': ['tokenCreationMin()'], + '0xd648a647': ['fundingStartBlock()'], + '0x3a1a635e': ['createNewRevision(bytes20,bytes32)'], + '0x7b760537': ['updateLatestRevision(bytes20,bytes32)'], + '0xa4b8c2e7': ['restart(bytes20,bytes32)'], + '0x22fa85ca': ['testFailRegisterContractAgain()'], + '0xcb56d626': ['testFailBlobStoreNotRegistered()'], + '0x6ec99dd0': ['testGetBlobStore()'], + '0x7604b6d7': ['testGetBlobStoreFromFullBlobId()'], + '0xc28bfe5a': ['testFailCreateSameIpfsHashAndNonce()'], + '0xded04fe9': ['testFailCreateNewRevisionNotOwner()'], + '0x9a93e940': ['testFailCreateNewRevisionNotUpdatable()'], + '0x960d8cd3': ['testFailUpdateLatestRevisionNotOwner()'], + '0x3ce1f4e7': ['testFailUpdateLatestRevisionNotUpdatable()'], + '0xf99ebb71': ['testFailUpdateLatestRevisionEnforceRevisions()'], + '0x251fa3b1': ['testFailRetractLatestRevisionNotOwner()'], + '0xb2ab530e': ['testFailRetractLatestRevisionNotUpdatable()'], + '0xc57a99e5': ['testFailRetractLatestRevisionEnforceRevisions()'], + '0xc204505a': [ + 'testFailRetractLatestRevisionDoesntHaveAdditionalRevisions()' + ], + '0x617f8666': ['testFailRestartNotOwner()'], + '0xd2c5c368': ['testFailRestartNotUpdatable()'], + '0xcf984f16': ['testFailRestartEnforceRevisions()'], + '0x3cc0fb45': ['testFailRetractNotOwner()'], + '0xa9888148': ['testFailRetractNotRetractable()'], + '0x71e60fe6': ['testFailTransferEnableNotTransferable()'], + '0x9acade7e': ['testFailTransferDisableNotEnabled()'], + '0xe2b8766c': ['testFailTransferNotTransferable()'], + '0x615f9f1f': ['testFailTransferNotEnabled()'], + '0x19ea61db': ['testFailTransferDisabled()'], + '0x776df027': ['testFailDisownNotOwner()'], + '0xeddce76b': ['testFailDisownNotTransferable()'], + '0x32d8eee5': ['testFailSetNotUpdatableNotOwner()'], + '0x6fe5b536': ['testFailSetEnforceRevisionsNotOwner()'], + '0xf2c2dff2': ['testFailSetNotRetractableNotOwner()'], + '0x5cc501ce': ['testFailSetNotTransferableNotOwner()'], + '0xf38e5ca2': ['getBlobStoreFromFullBlobId(bytes32)'], + '0x01e3d346': ['create(bytes1,bytes32,uint256)'], + '0x147a5640': ['_getAllRevisionIpfsHashes(bytes20)'], + '0x64d12ec6': ['getRevisionIpfsHash(bytes20,uint256)'], + '0x540c97c8': ['getAllRevisionIpfsHashes(bytes20)'], + '0xb7c38d02': ['testControlCreateSameIpfsHashAndNonce()'], + '0x6e1479c0': ['testControlCreateNewRevisionNotOwner()'], + '0xe73b7d77': ['testControlCreateNewRevisionNotUpdatable()'], + '0x8cdcdae1': ['testControlUpdateLatestRevisionNotOwner()'], + '0x69c5c229': ['testControlUpdateLatestRevisionNotUpdatable()'], + '0x80e74b04': ['testControlUpdateLatestRevisionEnforceRevisions()'], + '0x86602b6b': ['testControlRetractLatestRevisionNotOwner()'], + '0xc7a3778f': ['testControlRetractLatestRevisionNotUpdatable()'], + '0x6c712471': ['testControlRetractLatestRevisionEnforceRevisions()'], + '0x610285d2': [ + 'testControlRetractLatestRevisionDoesntHaveAdditionalRevisions()' + ], + '0xebc697d1': ['testControlRestartNotOwner()'], + '0x2d985cfb': ['testControlRestartNotUpdatable()'], + '0xcebb8bb0': ['testControlRestartEnforceRevisions()'], + '0xe37e60d1': ['testControlRetractNotOwner()'], + '0xcefdfcf3': ['testControlRetractNotRetractable()'], + '0x490825a9': ['testControlTransferEnableNotTransferable()'], + '0x20d615c2': ['testControlTransferDisableNotEnabled()'], + '0xe18c52ae': ['testControlTransferNotTransferable()'], + '0xe71d7bf0': ['testControlTransferNotEnabled()'], + '0x32bf775d': ['testControlTransferDisabled()'], + '0xb47784d9': ['testControlDisownNotOwner()'], + '0x98a29a58': ['testControlDisownNotTransferable()'], + '0x50a9eddb': ['testControlSetNotUpdatableNotOwner()'], + '0x0ec3b247': ['testControlSetEnforceRevisionsNotOwner()'], + '0xc3689f01': ['testControlSetNotRetractableNotOwner()'], + '0x9bf68006': ['testControlSetNotTransferableNotOwner()'], + '0x0ab03e1b': ['testControlRegisterContractAgain()'], + '0x895224db': ['testControlBlobStoreNotRegistered()'], + '0x81accd0b': ['create(bytes1,bytes32,bytes32)'], + '0x6013aa44': ['testControlCreateSameNonce()'], + '0x94106200': ['testFailCreateSameNonce()'], + '0x396ed0ab': ['Burn()'], + '0xd89135cd': ['totalBurned()'], + '0xf24e4a15': ['Purge()'], + '0x1caba41f': ['decimalUnits()'], + '0xc0463711': ['lastUpdate()'], + '0xe5a6b10f': ['currency()'], + '0x1820b575': ['Team(uint256,address,uint256)'], + '0x8a78f5e2': ['changeMember(address,bool,bool,uint256)'], + '0x30b0faab': ['changeSettings(uint256,address,uint256)'], + '0x03048a42': ['createRequest(address,uint256,string,bytes,bytes)'], + '0x17fb6c6e': ['approveRequest(uint256,bool,string)'], + '0x03ef2a2c': ['tryExecuteProposal(uint256,bytes)'], + '0x4ff6aa46': ['deactivateTeam()'], + '0x3f2885cb': ['publish(string,string,address,bytes32)'], + '0x50692d9a': ['toContentID(address,string,string,address,bytes32)'], + '0x7115c988': ['Batch(address)'], + '0x64eb7327': ['_getContent(bytes32)'], + '0x7ff0346b': ['getContents(bytes32[])'], + '0x2625e2e1': ['post(address,address,bytes32)'], + '0x534878fb': ['reply(address,address,bytes32,bytes32)'], + '0x7f602231': ['tip(bytes32,address,uint256)'], + '0x816e24b0': ['setupDeposits()'], + '0x68e7bdba': ['disableApi(address)'], + '0xbd322b77': ['enableApi(address)'], + '0x5cc15001': ['getContent(bytes32)'], + '0x9a01b4d5': ['getChannel(address)'], + '0xfbcbc0f1': ['getAccount(address)'], + '0xae9a0785': ['getChannelPostCount(address)'], + '0x5a17aa41': ['getContentTip(bytes32,address)'], + '0xd83a7f67': ['getDepositAddress(address)'], + '0xc489744b': ['getTokenBalance(address,address)'], + '0xe5c46944': ['MultiSigWallet(address[],uint256)'], + '0xe20056e6': ['replaceOwner(address,address)'], + '0xc6427474': ['submitTransaction(address,uint256,bytes)'], + '0x20ea8d86': ['revokeConfirmation(uint256)'], + '0xee22610b': ['executeTransaction(uint256)'], + '0x784547a7': ['isConfirmed(uint256)'], + '0xec096f8d': ['addTransaction(address,uint256,bytes)'], + '0x8b51d13f': ['getConfirmationCount(uint256)'], + '0x54741525': ['getTransactionCount(bool,bool)'], + '0xb5dc40c3': ['getConfirmations(uint256)'], + '0xa8abe69a': ['getTransactionIds(uint256,uint256,bool,bool)'], + '0x1914427f': ['MultiSigWalletWithDailyLimit(address[],uint256,uint256)'], + '0xcea08621': ['changeDailyLimit(uint256)'], + '0x811de206': ['isConfirmedByOwners(uint256)'], + '0x11c91914': ['isUnderLimit(uint256)'], + '0x4bc9fdc2': ['calcMaxWithdraw()'], + '0xae1a0b0c': ['launchLength()'], + '0x0a40f15f': ['fundDeal(string,address)'], + '0x1504ce95': ['payout(string)'], + '0x2de90801': ['hashtagToken()'], + '0x2e788443': ['resolve(string,address,uint256)'], + '0x5e717e2d': ['readDeal(string,address)'], + '0xac56c52b': ['makeDealForTwo(string,uint256)'], + '0xcdcf0c4a': ['dispute(string,address)'], + '0xf089b7dd': ['hashtag()'], + '0xf3227dc4': ['cancelDeal(string)'], + '0x3cebb823': ['changeController(address)'], + '0xf77c4791': ['controller()'], + '0x085d4883': ['provider()'], + '0x0e429ecc': ['providerValue()'], + '0x117de2fd': ['payout(address,uint256)'], + '0x200d2ed2': ['status()'], + '0x2e49d78b': ['setStatus(uint8)'], + '0x30cfac6c': ['assignTo(uint256,address,uint256)'], + '0xf3ab7ea9': ['seeker()'], + '0xfef1dc7d': ['seekerValue()'], + '0x0e4355d4': ['validFactories(address)'], + '0x10fe9ae8': ['getTokenAddress()'], + '0x29ce1ec5': ['addFactory(address)'], + '0x355e6b43': ['setCommission(uint256)'], + '0x4b37c73f': ['removeFactory(address)'], + '0x6985e46e': ['getConflictResolver()'], + '0x7f301b83': ['setMetadataHash(string)'], + '0x24664106': ['mintRep(int256,address,uint256)'], + '0xa4a75edc': ['registerDeal(address,address)'], + '0xaaf73ef7': ['registeredDeals()'], + '0xc5a1d7f0': ['metadataHash()'], + '0xcffee328': ['successfulDeals()'], + '0xe1489191': ['commission()'], + '0xf34f43f6': ['getRepTokenAddress()'], + '0xf6b44d03': ['validFactories()'], + '0x2dc2dbf2': ['makeSimpleDeal(address,address,uint256,bytes32)'], + '0x12424e3f': ['approve()'], + '0xb85477c5': ['dealStatus()'], + '0xe344606b': ['hashtagCommission()'], + '0x4a393149': ['onTransfer(address,address,uint256)'], + '0xda682aeb': ['onApprove(address,address,uint256)'], + '0xf48c3054': ['proxyPayment(address)'], + '0x55a373d6': ['tokenContract()'], + '0xc0112678': ['arcToken()'], + '0x921b2d64': ['mintTokens(int256,address,uint256)'], + '0x3290ce29': ['purchaseTokens()'], + '0x38cde380': ['changeWeight(uint256)'], + '0x4f995d08': ['getPeople()'], + '0x74607d91': ['patient(uint256)'], + '0x7b464e93': ['prescriptions(bytes32)'], + '0x86590955': ['changeHeight(uint256)'], + '0xd72dec33': ['changeVaccinHistory(address)'], + '0xdc3d4203': [ + 'createPatient(bytes32,bytes32,uint256,uint256,uint256,bytes32,uint256)' + ], + '0xe571fd2d': ['addPrescription(uint256,string)'], + '0xfbbf93a0': ['getDetails()'], + '0x077dadb2': ['coinBalanceMultisig(address)'], + '0x249b4d4f': ['transferContractUser(address)'], + '0x388f3cd3': ['cashin(address,uint256)'], + '0x527f4ff1': ['setTransferAddressUser(address,address)'], + '0x6ba2aefc': ['transferMultisig(address,address,uint256)'], + '0x9d16aca6': ['changeExchangeContract(address)'], + '0xd126dac4': ['cashout(address,address,uint256)'], + '0xf1679095': ['getTransferAddressUser(address)'], + '0x0bf77989': ['debug_coinbaseTxSha(bytes,uint256)'], + '0x107b1f8c': [ + 'debug_verifyShare(bytes,uint256[],uint256[],bytes,uint256,uint256)' + ], + '0x14ca5398': [ + 'submitFullBlock(bytes,uint256[],uint256[],bytes,bytes,bytes,bytes,bytes,bytes,uint256)' + ], + '0x2850c72a': ['debug_extendCoinbaseTxOutput(uint256,uint256)'], + '0x3e2ee39e': ['debug_resetuser()'], + '0x43c33ac9': ['submitShares(uint256,uint256)'], + '0x579d5fba': ['debug_hash3Int(uint256)'], + '0x83cd5e13': ['debug_multiplehash(uint256,uint256)'], + '0x88702cc4': ['debug_hash256Double(bytes)'], + '0x88f6d5a4': ['constructCoinbaseTx(uint256,uint256)'], + '0x9559225c': ['debug_hash3Byte(bytes)'], + '0x99d1d002': ['debug_blockHeaderMerkle(bytes)'], + '0xa68393a2': ['debug_getCoinbaseTxOutputLen(uint256)'], + '0xad076bfc': ['debug_hash256Double_concat(bytes,bytes,bytes)'], + '0xb2b0aefb': [ + 'verifyPendingShares(uint256[],uint256[],uint256,uint256[],uint256[],bytes,bytes,uint256)' + ], + '0xed47ca94': [ + 'debug_verifySharesTreeSubmission(uint256[],uint256[],uint256,uint256,uint256,uint256)' + ], + '0xf16fa954': ['debug_resizeRealPrefix(uint256,uint256)'], + '0x6104464f': ['previousPublishedVersion()'], + '0x6737c877': ['setAttributes(bytes)'], + '0x884179d8': ['ipfsAttributeLookup(address)'], + '0x9352fad2': ['run(string)'], + '0x98e7ea43': ['reward(uint32[],address[])'], + '0x0456860a': ['acceptAtCommunity(address,uint256)'], + '0x0a90c704': [ + 'createCommunity(string,string,string,string,uint256,uint256,uint256,uint256,uint256,uint256,uint256,bool,uint256,uint256,uint256)' + ], + '0x197f3c29': ['notLike(address)'], + '0x1b7db340': ['sysAdmin()'], + '0x2925ffc2': ['modifyCommunityTaxes(uint256,uint256,uint256,uint256)'], + '0x33b85b73': [ + 'modifyCommunityRates(uint256,uint256,uint256,uint256,uint256,bool,uint256,uint256,uint256)' + ], + '0x3500a48d': ['transferCommunityCommune(uint256,address)'], + '0x36b33415': ['modifyMemberInfo(string,string,string,string)'], + '0x47c66140': ['getProposalVotes(uint256)'], + '0x519a078f': ['getCommunitybyIndex(uint256)'], + '0x526b91d1': ['transferSysAdmin(address)'], + '0x52ea5667': ['getMPbyIndex(uint256)'], + '0x67a09c23': ['payment(address,uint256)'], + '0x71efeff1': ['transferCommunityBank(uint256,address)'], + '0x721a1f57': ['endorseCredit(address,uint256,uint256)'], + '0x84e10a90': ['getTotals()'], + '0x8b343e8f': ['getMemberCredit(address)'], + '0x9431e412': ['getCommunityRates(uint256)'], + '0xa5496e60': ['newProposal(uint256,string,string,uint256,uint256)'], + '0xad71c687': ['registerSystem(string,string,string,string)'], + '0xb122a0ef': ['joinCommunity(uint256)'], + '0xbcabb54c': ['modifyCommunityInfo(uint256,string,string,string,string)'], + '0xbfb04c60': ['proposeAcceptanceAsMember(uint256)'], + '0xd21cbffc': ['getIfVoted(uint256,address)'], + '0xd95ab72d': ['getMemberWallet(address)'], + '0xdde8535f': ['getMemberStatus(address)'], + '0xe05e3028': ['getCommunityManagement(uint256)'], + '0xe465c465': ['like(address)'], + '0xee650248': ['vote(uint256,int8)'], + '0xf47efbca': ['getMemberLinks(address)'], + '0xf6df26d2': ['kickOutCommunity(address,uint256)'], + '0xf82c2301': ['resignFromCommunity()'], + '0xfba6651c': ['getCommunityTaxes(uint256)'], + '0xfcc101ba': ['getCommunityDescription(uint256)'], + '0x04029f23': ['_setBugFixVersion(string,uint32,bytes32,uint32)'], + '0x1f9ea25d': ['_setDepositAccount(address)'], + '0x49593f53': ['submit(string,uint64,uint32,uint32,bytes32)'], + '0x569aa0d8': ['getPlayerSubmissionFromCompetition(string,uint8,address)'], + '0x59a4669f': ['increaseJackpot(string)'], + '0x656104f5': ['_setOrganiser(address)'], + '0x70de8c6e': ['start(string,uint64,uint8,uint32)'], + '0x71bde852': [ + '_startNextCompetition(string,uint32,uint88,uint8,uint8,uint16,uint64,uint32,bytes32,uint32[])' + ], + '0x8d909ad9': ['getSeedAndState(string,address)'], + '0x8f30435d': ['getCompetitionValues(string,uint8)'], + '0x916dbc17': ['getPlayersFromCompetition(string,uint8)'], + '0xc91540f6': ['getCurrentCompetitionValues(string)'], + '0xfedc2a28': ['_rewardWinners(string,uint8,address[])'], + '0x224ccc49': ['chainLastMessageHash(bytes32)'], + '0x482f63b0': ['postMessage(bytes32,bytes)'], + '0x590a4595': ['createNewChain(bytes)'], + '0x858c7559': ['chainIDSeed()'], + '0x52c98e33': ['checkClaim(address,uint256,uint256)'], + '0x598aa1fc': ['checkEndorsement(address,uint256,address)'], + '0xa16c6a73': ['setClaim(uint256,uint256)'], + '0xa1bdd146': ['setEndorsement(address,uint256,uint256)'], + '0xa3a48785': ['unsetClaim(uint256)'], + '0xd7789a9f': ['unsetEndorsement(address,uint256)'], + '0xa9d0ddc7': ['addContractWithInfo(string,string)'], + '0xfa3559f7': ['attestToContract(uint256,bool,string)'], + '0x179fc99f': ['etherBalanceOf(address)'], + '0x3b0c197e': ['getBook()'], + '0x42da3b6b': ['getAmount(uint256,address)'], + '0x6dee2032': ['getOpenOrdersOf(address)'], + '0x836e4158': ['numOrdersOf(address)'], + '0x8ab1a5d4': ['sell(uint256,uint256,bool)'], + '0x8b7afe2e': ['contractBalance()'], + '0x8c3f914a': ['spread(bool)'], + '0x8f70ccf7': ['setTrading(bool)'], + '0x975289fd': ['getPriceVolume(uint256)'], + '0xc3434883': ['buy(uint256,uint256,bool)'], + '0xd07866d2': ['sizeOf(uint256)'], + '0xe1725c92': ['decimalPlaces()'], + '0xe2dede94': ['getNode(uint256,uint256)'], + '0xec44acf2': ['trading()'], + '0x11456b47': ['addName(string)'], + '0x14bfd6d0': ['admins(uint256)'], + '0x4deb68a3': ['auctionStart(bytes32,uint256,uint256)'], + '0x663e90d9': ['setBuyNowListing(bytes32,uint256,bool)'], + '0x71c79588': ['releaseName(bytes32)'], + '0x7c72e273': ['auctionFinalize(bytes32)'], + '0x9bdd7cdb': ['forceRelease(bytes32)'], + '0xbfcf63b0': ['claimEther(address,uint256)'], + '0xc415b95c': ['feeCollector()'], + '0xd7ad4931': ['buyNow(bytes32)'], + '0xe2acf75d': ['auctionCancel(bytes32)'], + '0xf747a5eb': ['auctionBid(bytes32)'], + '0x13831693': ['getLevitatingUnicorns(bytes32,uint64)'], + '0x50fe533b': ['getLevitatingBirds(bytes32,uint64)'], + '0xc9aa71b8': ['getFlyingUnicorns(bytes32,uint64)'], + '0xfeb50430': ['getLevitatingKittens(bytes32,uint64)'], + '0x78c2c849': ['burnUnicorns()'], + '0xbd8b452e': ['eatUnicorns()'], + '0x4b06fb28': ['eatUnicornsAlive()'], + '0x5b303e16': ['eatUnicorns(uint256)'], + '0xa1e95792': ['eatUnicornsAlive(uint256)'], + '0x10867877': ['eatUnicornWithoutCorn()'], + '0x4b269a00': ['withdraw(int256[])'], + '0x2c7cce9e': ['auctionMinPriceIncrease()'], + '0x801c334e': ['auctionIncreaseBid(bytes32)'], + '0x95e911a8': ['feeBase()'], + '0xb4628c8a': ['ENSRegistrar()'], + '0xddca3f43': ['fee()'], + '0xe765cb44': ['auctionMinPrice()'], + '0x69f30401': ['bid(address,uint256[],uint256[])'], + '0x6e67b803': ['bid3(address,uint256[],uint256[])'], + '0x21462191': ['bid3(address,uint8[],uint8[])'], + '0x92584d80': ['finalize(bytes32)'], + '0xf3bf93a0': ['forceReleaseAdmin(bytes32)'], + '0x5b372532': ['press()'], + '0x9f095e88': ['asdf()'], + '0xb0459d49': [ + 'LoanStandard(address,address,uint256,uint256,uint256,uint256,uint256)' + ], + '0xa2fb342d': ['lend(address,uint256)'], + '0xd334d75b': ['expireLoan()'], + '0xb7019744': ['payBack(address,uint256)'], + '0x60aeac18': ['neverPayBack()'], + '0xaad3ec96': ['claim(address,uint256)'], + '0x4c123019': ['tokenFallback(address,address,uint256,bytes)'], + '0xcb7acdd9': ['hola()'], + '0xacb6e9b1': ['testControlItemStoreNotRegistered()'], + '0xac767539': ['testFailItemStoreNotRegistered()'], + '0x1649cdcd': ['testGetItemStore()'], + '0xe41cc093': ['getItemStore(bytes12)'], + '0x79ba5097': ['acceptOwnership()'], + '0x58e9b208': ['Controlled()'], + '0x30311898': ['Account(address)'], + '0xce3f865f': ['collect(uint256)'], + '0x55ee6afb': ['Wallet(address,address)'], + '0x2268a358': ['changeMultisig(address)'], + '0xea2c23da': ['createAccounts(uint256)'], + '0xa5e8c5d6': ['setVoteRight(address,uint256)'], + '0x9cc0c5e3': ['experty_io()'], + '0x5022e940': ['experty()'], + '0xb7090bb5': ['www_experty_io()'], + '0x0edfb0f7': ['withdrawCollectedInterest()'], + '0x21856b36': ['interestOwed()'], + '0x402d8883': ['repay()'], + '0x4665096d': ['expiration()'], + '0x58f33e98': ['isTaker(address)'], + '0x5eda5b9a': ['interestCollected()'], + '0x6cbdb7d0': ['takers(uint256)'], + '0x7c3a00fd': ['interestRate()'], + '0xaa8116be': ['fundedPrincipal()'], + '0xbc99c8be': ['takerAddressAt(uint256)'], + '0xc41f4cc0': ['takerStatus(address)'], + '0xc537a210': ['principalOutstanding()'], + '0xc5ebeaec': ['borrow(uint256)'], + '0xcb6da9da': ['takerCount()'], + '0xfb775b46': ['giver()'], + '0xe1a27ad3': ['needsAdministration()'], + '0xb6253539': ['needsInitialization()'], + '0xb6f98e53': ['needsAllowancePayment()'], + '0xb5931f7c': ['safeDiv(uint256,uint256)'], + '0x3a4faf7f': ['max64(uint64,uint64)'], + '0x36b1315c': ['min64(uint64,uint64)'], + '0x0c255c94': ['max256(uint256,uint256)'], + '0xb1e9292f': ['min256(uint256,uint256)'], + '0x1d3b9edf': ['times(uint256,uint256)'], + '0xf4f3bdc1': ['minus(uint256,uint256)'], + '0x66098d4f': ['plus(uint256,uint256)'], + '0x8afc3605': ['Ownable()'], + '0x04bbc255': ['isPricingStrategy()'], + '0x8e768288': ['isSane(address)'], + '0x18a4155e': ['calculatePrice(uint256,uint256,uint256,address,uint256)'], + '0x614cb904': ['isFinalizeAgent()'], + '0x82771c8e': ['isSane()'], + '0x0bf318a3': ['finalizeCrowdsale()'], + '0x96f47800': ['investInternal(address,uint128)'], + '0x32013ac3': ['preallocate(address,uint256,uint256)'], + '0x1a49803b': [ + 'investWithSignedAddress(address,uint128,uint8,bytes32,bytes32)' + ], + '0xef869443': ['investWithCustomerId(address,uint128)'], + '0x03f9c793': ['invest(address)'], + '0xf4869726': ['buyWithSignedAddress(uint128,uint8,bytes32,bytes32)'], + '0x99e9376c': ['buyWithCustomerId(uint128)'], + '0x7f7d711e': ['setRequireCustomerId(bool)'], + '0xed68ff2c': ['setRequireSignedAddress(bool,address)'], + '0xeac24932': ['setEarlyParicipantWhitelist(address,bool)'], + '0x6e50eb3f': ['setEndsAt(uint256)'], + '0xf3283fba': ['setMultisig(address)'], + '0x87612102': ['loadRefund()'], + '0x7c2e08a3': ['isMinimumGoalReached()'], + '0xa7ba44c3': ['isFinalizerSane()'], + '0x062b01ce': ['isPricingSane()'], + '0x1865c57d': ['getState()'], + '0x8d51faec': ['setOwnerTestValue(uint256)'], + '0x4551dd59': ['isCrowdsale()'], + '0x9d3c663f': ['isBreakingCap(uint256,uint256,uint256,uint256)'], + '0xd5d09021': ['isCrowdsaleFull()'], + '0x4d7edc15': ['assignTokens(address,uint256)'], + '0xeefa597b': ['isToken()'], + '0x09ae9452': ['PreICOProxyBuyer(address,uint256,uint256,uint256,uint256)'], + '0x21df0da7': ['getToken()'], + '0xbaeb91ae': ['invest(uint128)'], + '0x1fb00cdc': ['investWithId(uint128)'], + '0xdbb833df': ['investWithoutId()'], + '0xd4607048': ['buyForEverybody()'], + '0xdde070e8': ['getClaimAmount(address)'], + '0x3c67b6b7': ['getClaimLeft(address)'], + '0xd1058e59': ['claimAll()'], + '0x4042b66f': ['weiRaised()'], + '0xf6368f8a': ['transfer(address,uint256,bytes,string)'], + '0x3ef13367': ['flushTokens(address)'], + '0x083c6323': ['endBlock()'], + '0x7055060f': ['bulkStoreHeader(bytes)'], + '0x3115b4c4': ['bulkStoreHeader(bytes,uint256)'], + '0x01725a0b': ['demo()'], + '0xdce5c757': ['cool()'], + '0x939a79ac': ['demo(string)'], + '0x071bd079': ['demo(uint256)'], + '0x43b1c529': ['getSig(string,bytes4)'], + '0x1d03842f': ['onePlus(uint256)'], + '0x42966c68': ['burn(uint256)'], + '0x457f4d41': ['hammer()'], + '0x58292a3d': ['emission(uint256)'], + '0xd31fdffd': ['setHammer(address)'], + '0xb8c48f8c': ['setInitialParent(int256,int256,int256)'], + '0x08f75d17': ['move_reveal(bytes32,uint8)'], + '0x2e9c91a8': ['getStartParams(bytes32)'], + '0x497777d5': ['collect(bytes32)'], + '0x5598c576': ['reveal_move(bytes32,uint8,bytes32,bytes32)'], + '0x5cf34bcf': ['getMinFee()'], + '0x6a7bf76a': [ + 'create_game(bytes32,uint32,uint32,uint8,uint16,uint8,address,uint256,bool)' + ], + '0x73931bbf': ['getGame(bytes32)'], + '0x87287fd7': ['setMinFee(uint8)'], + '0x89d61d77': ['setOrganizer(address)'], + '0xa361b184': ['move(bytes32,bytes32)'], + '0xe4083daf': [ + 'create_game_invite(bytes32,address,uint32,uint32,uint8,uint16,uint8,address,uint256)' + ], + '0xf223446c': [ + 'start_game(bytes32,uint8,uint32,uint16,address,uint256,uint8)' + ], + '0x3a4de190': ['repost(bytes32)'], + '0x4b91ab35': ['unfollow(bytes32)'], + '0x66e34dc6': ['registerUsername(bytes32)'], + '0x699f200f': ['addresses(bytes32)'], + '0x7e93163b': ['tip(bytes32,bytes32)'], + '0x8ee93cf3': ['post(string)'], + '0x9d7eb375': ['updateUserDetails(string)'], + '0xa66b7748': ['follow(bytes32)'], + '0xa83b1e21': ['reply(string,bytes32)'], + '0xd38d0f28': ['updateSplit(uint256)'], + '0xee91877c': ['usernames(address)'], + '0xf59823cf': ['Congress(uint256,uint256,int256)'], + '0xb3bb9b58': ['LiquidDemocracy(address,string,uint256)'], + '0x6dd7d8ea': ['vote(address)'], + '0xc0d061f4': ['execute(address,uint256,bytes32)'], + '0xf2ba18ed': ['calculateVotes()'], + '0xb154224e': ['TimeLockMultisig(address,address[],uint256)'], + '0x15bef9cd': ['changeMembers(address[],bool)'], + '0xc01f9e37': ['proposalDeadline(uint256)'], + '0x159887d1': ['calculateFactor(uint256,uint256)'], + '0x7207c19f': ['MyToken(uint256)'], + '0x73e9f3e6': ['Crowdsale(address,uint256,uint256,uint256,address,address)'], + '0xfd6b7ef8': ['safeWithdrawal()'], + '0x9dbf0087': ['TokenERC20(uint256,string,string)'], + '0x79cc6790': ['burnFrom(address,uint256)'], + '0x7e4f6b95': ['MyAdvancedToken(uint256,string,string)'], + '0xbc0c868c': ['stocksOf(uint256)'], + '0x8262fc7d': ['addrBalance(address)'], + '0x6dfe869b': ['Preallocation(address,uint256)'], + '0xa357880d': ['whitelistedAddrs(address)'], + '0x54da5393': ['Utils()'], + '0xe4edf852': ['transferManagement(address)'], + '0xc8c2fe6c': ['acceptManagement()'], + '0x67cc4882': ['TokenHolder()'], + '0x21e6b53d': ['transferTokenOwnership(address)'], + '0x38a5e016': ['acceptTokenOwnership()'], + '0x85d5e631': ['disableTokenTransfers(bool)'], + '0x205c2878': ['withdrawTo(address,uint256)'], + '0x1608f18f': ['disableTransfers(bool)'], + '0x29a00e7c': ['calculatePurchaseReturn(uint256,uint256,uint32,uint256)'], + '0x49f9b0f7': ['calculateSaleReturn(uint256,uint256,uint32,uint256)'], + '0x59f8714b': ['changeableTokenCount()'], + '0x503adbf6': ['changeableToken(uint16)'], + '0x9b99a8e2': ['reserveTokenCount()'], + '0x4e2280c4': ['clearQuickBuyPath()'], + '0x9396a7f0': ['getQuickBuyPathLength()'], + '0xabeb5f9f': ['hasQuickBuyEtherToken()'], + '0xb3a9afb7': ['getQuickBuyEtherToken()'], + '0x0b3f191a': ['disableChanging(bool)'], + '0x88c0b8a7': ['setChangeFee(uint32)'], + '0x48d6ca55': ['getChangeFeeAmount(uint256)'], + '0x7758c4f8': ['quickBuy(uint256)'], + '0x74214c92': ['StandardERC223Token(uint256)'], + '0x16279055': ['isContract(address)'], + '0x03ba3a88': ['notifyContract(address,address,uint256,bytes)'], + '0x27e235e3': ['balances(address)'], + '0x3f4ba83a': ['unpause()'], + '0x5c658165': ['allowed(address,address)'], + '0x5c975abb': ['paused()'], + '0x8456cb59': ['pause()'], + '0xa0821be3': ['availableBalance(address)'], + '0xe9ed8667': ['balanceLocks(address)'], + '0xf339c504': ['lockBalance(uint256)'], + '0x1d4d691d': [ + 'fill(address,uint256,address,address,uint256,address,uint256,uint256,uint8,bytes32,bytes32)' + ], + '0x20158c44': ['fills(bytes32)'], + '0x66a26419': [ + 'cancel(address,uint256,address,address,uint256,address,uint256,uint256,uint8,bytes32,bytes32)' + ], + '0x673a5ae3': [ + 'Sale(address,address,uint256,string,uint8,string,uint256,uint256,uint256,uint256,uint256,uint256)' + ], + '0x94b5255b': ['distributePreBuyersRewards(address[],uint256[])'], + '0x555c4758': [ + 'distributeTimelockedTokens(address[],uint256[],uint256[],uint256[])' + ], + '0x8b9b1cbd': ['withdrawRemainder()'], + '0xa2b40d19': ['changePrice(uint256)'], + '0x98b9a2dc': ['changeWallet(address)'], + '0x5437f098': ['changeStartBlock(uint256)'], + '0x82222674': ['changeEndBlock(uint256)'], + '0x00a53598': ['emergencyToggle()'], + '0xe382b854': ['_setPackedTimestamp(bytes20,uint256)'], + '0x31861423': ['_deleteAllPackedRevisionTimestamps(bytes20)'], + '0x4ae6ab70': ['_getRevisionTimestamp(bytes20,uint256)'], + '0x4e57d27d': ['_getAllRevisionTimestamps(bytes20)'], + '0xc5cd3bec': ['getRevisionTimestamp(bytes20,uint256)'], + '0x261c42dd': ['getAllRevisionTimestamps(bytes20)'], + '0x50035eb8': ['getInUse(bytes20)'], + '0xf25e7bb4': ['getState(bytes20)'], + '0x634bc7db': ['create(bytes32,bytes32)'], + '0xb0673d57': ['getItemStore(bytes32)'], + '0x455ea98c': ['getInUse(bytes32)'], + '0xa6c09381': ['_setPackedTimestamp(bytes32,uint256)'], + '0x001a4f5e': ['createNewRevision(bytes32,bytes32)'], + '0x032b0824': ['updateLatestRevision(bytes32,bytes32)'], + '0x1b5710ed': ['_deleteAllPackedRevisionTimestamps(bytes32)'], + '0x165ffd10': ['restart(bytes32,bytes32)'], + '0x2ab7d104': ['_getAllRevisionIpfsHashes(bytes32)'], + '0xf50f1ba9': ['_getRevisionTimestamp(bytes32,uint256)'], + '0xcd22f418': ['_getAllRevisionTimestamps(bytes32)'], + '0x09648a9d': ['getState(bytes32)'], + '0x72cef34b': ['getRevisionIpfsHash(bytes32,uint256)'], + '0x7c699401': ['getAllRevisionIpfsHashes(bytes32)'], + '0x05664cea': ['getRevisionTimestamp(bytes32,uint256)'], + '0x8cb3728c': ['getAllRevisionTimestamps(bytes32)'], + '0x93c8b0d4': ['addForeignChild(bytes32,bytes32)'], + '0x4048c449': ['getParent(bytes32)'], + '0x31230e23': ['createWithParent(bytes32,bytes32,bytes32)'], + '0x2eaad0b0': ['_getAllChildren(bytes32)'], + '0xa09e3d0a': ['getChildCount(bytes32)'], + '0x958d1725': ['getChild(bytes32,uint256)'], + '0xfbdf0378': ['getAllChildren(bytes32)'], + '0x9643aef4': ['testControlCreateWithParentSameNonce()'], + '0x8dc1c44d': ['testFailCreateWithParentSameNonce()'], + '0x2aaf1685': ['testControlCreateWithParentSameItemId()'], + '0xa121d8df': ['testFailCreateWithParentSameItemId()'], + '0x64d0d64c': ['testControlCreateWithParentNotInUse()'], + '0x75f208bf': ['testFailCreateWithParentNotInUse()'], + '0x473ae9fe': ['testCreateWithParent()'], + '0x59e1667d': ['testControlCreateWithForeignParentNotInUse()'], + '0xca615662': ['testFailCreateWithForeignParentNotInUse()'], + '0x121f2081': ['testCreateWithForeignParent()'], + '0xfc13a76a': ['testFailAddForeignChildNotInUse()'], + '0x4e6c61aa': ['testFailAddForeignChildNotChild()'], + '0x590ba734': ['getUint(int256)'], + '0x732e632e': ['assemblyTest()'], + '0x215de48a': ['getParentCount(bytes32)'], + '0x33ac7256': ['getParent(bytes32,uint256)'], + '0x32c4903d': ['getAllParents(bytes32)'], + '0x6844ab43': ['testControlCreateSameItemId()'], + '0x343f40a0': ['testFailCreateSameItemId()'], + '0x9d9c9a0d': ['testControlCreateWithParentParentSameItemId()'], + '0x3ce54ac3': ['testFailCreateWithParentParentSameItemId()'], + '0xbca9e546': ['testControlCreateWithParentParentNotInUse()'], + '0xbab9fc63': ['testFailCreateWithParentParentNotInUse()'], + '0x30840c31': ['testControlCreateWithParentForeignNotInUse()'], + '0x3d6b0cb7': ['testFailCreateWithParentForeignNotInUse()'], + '0x0de04691': ['testCreateWithParentForeign()'], + '0x3d608572': ['testControlCreateWithParentsSameItemId()'], + '0xba907b7e': ['testFailCreateWithParentsSameItemId()'], + '0x015689c6': ['testControlCreateWithParentsParentSameItemId()'], + '0x28e47076': ['testFailCreateWithParentsParentSameItemId0()'], + '0x8a7ef3df': ['testFailCreateWithParentsParentSameItemId1()'], + '0x041dd3f6': ['testControlCreateWithParentsParentNotInUse()'], + '0x46d47cdf': ['testFailCreateWithParentsParentNotInUse0()'], + '0x89a45223': ['testFailCreateWithParentsParentNotInUse1()'], + '0x44019db3': ['testCreateWithParents()'], + '0xbf0d44d5': ['testControlCreateWithParentsForeignNotInUse()'], + '0x0ee8e338': ['testFailCreateWithParentsForeignNotInUse0()'], + '0xdddb983b': ['testFailCreateWithParentsForeignNotInUse1()'], + '0xf94497fe': ['testCreateWithParentsForeign0()'], + '0xf6951038': ['testCreateWithParentsForeign1()'], + '0x26d3e889': ['testCreateWithParentsForeign2()'], + '0x98f69aeb': ['_addChildToParent(bytes32,bytes32)'], + '0x7fdd458d': ['createWithParents(bytes32,bytes32,bytes32[])'], + '0xa300eadf': ['_getAllParents(bytes32)'], + '0xa172045d': ['PUSH1()'], + '0x22a7118d': ['buyTokensFor(uint256,address,uint256,bool)'], + '0x9e1a00aa': ['sendTo(address,uint256)'], + '0x00b172d7': ['buyTokensForProposal(uint256,address)'], + '0x4913732e': ['buyTokenFromModerator(uint256,address,uint256,bool)'], + '0xdb6a3652': ['addOrder(address,uint256)'], + '0x9645337a': ['removeOrder(uint256)'], + '0x709ef231': ['sellTokens(uint256,uint256,uint256)'], + '0x868eb6bf': ['removeOrders(uint256,uint256)'], + '0x02d05d3f': ['creator()'], + '0x1f21f9af': ['marketMaker()'], + '0x28c05d32': ['shortSell(uint8,uint256,uint256)'], + '0x46280a80': ['sell(uint8,uint256,uint256)'], + '0x476343ee': ['withdrawFees()'], + '0x59acb42c': ['createdAtBlock()'], + '0xa157979c': ['netOutcomeTokensSold(uint256)'], + '0xb0011509': ['calcMarketFee(uint256)'], + '0xcb4c86b7': ['funding()'], + '0xe274fd24': ['eventContract()'], + '0xf6d956df': ['buy(uint8,uint256,uint256)'], + '0xfbde47f6': ['FEE_RANGE()'], + '0x27793f87': ['outcome()'], + '0x717a195a': ['setOutcome(int256)'], + '0x7e7e4b47': ['getOutcome()'], + '0xc623674f': ['ipfsHash()'], + '0xc65fb380': ['isSet()'], + '0xccdf68f3': ['isOutcomeSet()'], + '0x4e2f220c': ['createCentralizedOracle(bytes)'], + '0x5ea194a3': ['createScalarEvent(address,address,int256,int256)'], + '0x8d1d2c21': ['categoricalEvents(bytes32)'], + '0x9897e8a5': ['scalarEvents(bytes32)'], + '0x9df0c176': ['createCategoricalEvent(address,address,uint8)'], + '0xeac449d9': ['revoke(address,uint256)'], + '0x7abeb6a0': ['createMarket(address,address,uint24)'], + '0x42958b54': ['issue(address[],uint256)'], + '0x061a85c7': ['forwardedOracle()'], + '0x0853f7eb': ['frontRunnerPeriod()'], + '0x0f3e9438': ['frontRunner()'], + '0x1a39d8ef': ['totalAmount()'], + '0x1a4f5b67': ['isFrontRunnerPeriodOver()'], + '0x1ff14311': ['totalOutcomeAmounts(int256)'], + '0x466ae314': ['forwardedOutcomeSetTimestamp()'], + '0x72b8de14': ['isChallengePeriodOver()'], + '0x739b8c48': ['setForwardedOutcome()'], + '0x8ef8125e': ['frontRunnerSetTimestamp()'], + '0x984a470a': ['forwardedOutcome()'], + '0x9d89e7d4': ['challengeAmount()'], + '0x9df4d0fe': ['isChallenged()'], + '0x9f0de490': ['challengeOutcome(int256)'], + '0xb2016bd4': ['collateralToken()'], + '0xc427af9b': ['outcomeAmounts(address,int256)'], + '0xd84d2a47': ['spreadMultiplier()'], + '0xf3f480d9': ['challengePeriod()'], + '0xf7553098': ['voteForOutcome(int256,uint256)'], + '0xce70faec': [ + 'createUltimateOracle(address,address,uint8,uint256,uint256,uint256)' + ], + '0x91e8609f': ['getParentId(bytes32,uint256)'], + '0xb4a39dfd': ['getChildId(bytes32,uint256)'], + '0x5de4381b': ['_addItemToParent(bytes32,bytes32)'], + '0x059417da': ['_getAllParentIds(bytes32)'], + '0xeca85419': ['_getAllChildIds(bytes32)'], + '0xaa0372e7': ['getItem(bytes32)'], + '0xdcf946c2': ['getAllParentIds(bytes32)'], + '0x1733043f': ['getAllChildIds(bytes32)'], + '0x025e7c27': ['owners(uint256)'], + '0x0cbe1eb8': ['USDDOWNLOADPRICE()'], + '0x11851b5e': ['BOARD_3()'], + '0x1e9be6a1': ['usdEthPrice()'], + '0x3c540687': ['txCount()'], + '0x436da5fe': ['transferLog(uint256)'], + '0x44fddeb7': ['BLOCKAPPS()'], + '0x52aaead8': ['priceLastUpdated()'], + '0x6695b592': ['stemPriceInWei()'], + '0x7dc0d1d0': ['oracle()'], + '0x7fa28d75': ['transferRightIfApproved(address,bytes32)'], + '0x83db0680': ['TOTALSHARES()'], + '0x977eda79': ['txLog(uint256)'], + '0xb9488546': ['ownersCount()'], + '0xcc445611': ['purchase(bytes32)'], + '0xda60d7e8': ['BOARD_2()'], + '0xe347a773': ['shares(bytes32,bytes32)'], + '0xe3d33fc9': ['transferCount()'], + '0xe80d47dd': ['USDSTEMPRICE()'], + '0xf267035f': ['BOARD_1()'], + '0xf7701b47': ['downloadPriceInWei()'], + '0xf851a440': ['admin()'], + '0x8a252194': ['betGanjilGenap(bool)'], + '0xa89171e3': ['checkHasilBet(address)'], + '0xdd365b8b': ['pwn()'], + '0x0537665d': ['setOutcome()'], + '0x28da850b': ['buyAllOutcomes(uint256)'], + '0x69c19d4c': ['getOutcomeTokenDistribution(address)'], + '0x6fb1edcd': ['sellAllOutcomes(uint256)'], + '0x7dc8f086': ['getOutcomeCount()'], + '0x8abe59ea': ['outcomeTokens(uint256)'], + '0xad0b2bec': ['redeemWinnings()'], + '0xe96e5950': ['getEventHash()'], + '0xf21a1468': ['getOutcomeTokens()'], + '0x561cce0a': ['LONG()'], + '0x6e5452fe': ['OUTCOME_RANGE()'], + '0xa384d6ff': ['lowerBound()'], + '0xa871da91': ['SHORT()'], + '0xb09ad8a0': ['upperBound()'], + '0x0a6fbb05': ['SetPass(bytes32)'], + '0x31fd725a': ['PassHasBeenSet(bytes32)'], + '0x6cd5c39b': ['deployContract()'], + '0xe79487da': ['checkInvariant()'] +}; diff --git a/interface/client/lib/thirdParty.js b/interface/client/lib/thirdParty.js new file mode 100644 index 0000000..26c109f --- /dev/null +++ b/interface/client/lib/thirdParty.js @@ -0,0 +1,19 @@ +// set spinner options +Meteor.Spinner.options = { + lines: 12, // The number of lines to draw + length: 0, // The length of each line + width: 4, // The line thickness + radius: 8, // The radius of the inner circle + corners: 1, // Corner roundness (0..1) + rotate: 0, // The rotation offset + direction: 1, // 1: clockwise, -1: counterclockwise + color: '#000', // #rgb or #rrggbb or array of colors + speed: 1.7, // Rounds per second + trail: 49, // Afterglow percentage + shadow: false, // Whether to render a shadow + hwaccel: false, // Whether to use hardware acceleration + className: 'spinner', // The CSS class to assign to the spinner + zIndex: 2e9, // The z-index (defaults to 2000000000) + top: '50%', // Top position relative to parent + left: '50%' // Left position relative to parent +}; diff --git a/interface/client/mistAPIBackend.js b/interface/client/mistAPIBackend.js new file mode 100644 index 0000000..6a23de9 --- /dev/null +++ b/interface/client/mistAPIBackend.js @@ -0,0 +1,155 @@ +/** +@module MistAPI Backend +*/ + +var allowedBrowserBarStyles = ['transparent']; + +/** +Filters a id the id to only contain a-z A-Z 0-9 _ -. + +@method filterId +*/ +var filterId = function(str) { + var newStr = ''; + var i; + for (i = 0; i < str.length; i += 1) { + if (/[a-zA-Z0-9_-]/.test(str.charAt(i))) { + newStr += str.charAt(i); + } + } + return newStr; +}; + +var sound = document.createElement('audio'); + +/** +The backend side of the mist API. + +@method mistAPIBackend +*/ +mistAPIBackend = function(event) { + var template = this.template; + var webview = this.webview; + var arg = event.args[0]; + + // console.trace('mistAPIBackend event', event); + + if (event.channel === 'setWebviewId') { + Tabs.update(template.data._id, { + $set: { webviewId: webview.getWebContents().id } + }); + } + + // Send TEST DATA + if (event.channel === 'sendTestData') { + var tests = Tabs.findOne('tests'); + + if (tests) { + web3.eth.getCoinbase(function(e, coinbase) { + webview.send('uiAction_sendTestData', tests.permissions, coinbase); + }); + } + } + + // SET FAVICON + if (event.channel === 'favicon') { + Tabs.update(template.data._id, { + $set: { + icon: Blaze._escape(arg || '') + } + }); + } + + // SET APPBAR + if (event.channel === 'appBar') { + var appBarClass = Blaze._escape(arg || ''); + + Tabs.update(template.data._id, { + $set: { + appBar: _.contains(allowedBrowserBarStyles, appBarClass) + ? appBarClass + : null + } + }); + } + if (event.channel === 'mistAPI_sound') { + sound.pause(); + sound.src = Blaze._escape('file://' + dirname + '/sounds/' + arg + '.mp3'); + sound.play(); + } + + // STOP HERE, IF BROWSER + if (template.data._id === 'browser') { + return; + } + + // Actions: -------- + + if (event.channel === 'mistAPI_setBadge') { + Tabs.update(template.data._id, { + $set: { + badge: arg + } + }); + } + + if (event.channel === 'mistAPI_menuChanges' && arg instanceof Array) { + arg.forEach(function(eventArg) { + var query; + + if (eventArg.action === 'addMenu') { + // filter ID + if (eventArg.entry && eventArg.entry.id) { + eventArg.entry.id = filterId(eventArg.entry.id); + } + + query = { $set: {} }; + + if (eventArg.entry.id) { + query.$set['menu.' + eventArg.entry.id + '.id'] = eventArg.entry.id; + } + + query.$set['menu.' + eventArg.entry.id + '.selected'] = !!eventArg.entry + .selected; + + if (!_.isUndefined(eventArg.entry.position)) { + query.$set['menu.' + eventArg.entry.id + '.position'] = + eventArg.entry.position; + } + if (!_.isUndefined(eventArg.entry.name)) { + query.$set['menu.' + eventArg.entry.id + '.name'] = + eventArg.entry.name; + } + if (!_.isUndefined(eventArg.entry.badge)) { + query.$set['menu.' + eventArg.entry.id + '.badge'] = + eventArg.entry.badge; + } + + Tabs.update(template.data._id, query); + } + + if (eventArg.action === 'selectMenu') { + var tab = Tabs.findOne(template.data._id); + + for (var e in tab.menu) { + if ({}.hasOwnProperty.call(tab.menu, e)) { + tab.menu[e].selected = e === eventArg.id; + } + } + Tabs.update(template.data._id, { $set: { menu: tab.menu } }); + } + + if (eventArg.action === 'removeMenu') { + var removeQuery = { $unset: {} }; + + removeQuery.$unset['menu.' + eventArg.id] = ''; + + Tabs.update(template.data._id, removeQuery); + } + + if (eventArg.action === 'clearMenu') { + Tabs.update(template.data._id, { $set: { menu: {} } }); + } + }); + } +}; diff --git a/interface/client/styles/animations.import.less b/interface/client/styles/animations.import.less new file mode 100644 index 0000000..8b218c2 --- /dev/null +++ b/interface/client/styles/animations.import.less @@ -0,0 +1,61 @@ +// Menu + +aside.sidebar { + ul li { + transition: transform 0.25s, height 0.25s, visibility 0.5s; + + &.ui-sortable-helper { + transition: none; + } + + button.slide-out { + transition: transform 0.2s ease-in-out; + } + + ul.sub-menu { + li { + transition: background 0.05s ease-in-out, height 0.25s ease-out, + opacity 0.25s ease-out; + } + .badge { + // ANIMATION + transition: max-width @animationSpeed; + } + } + } +} + +// Browser bar +.browser-bar { + .url-input { + transition: opacity 0.1s; + } +} + +.popup-windows { + position: relative; + perspective: 800px; + + .field-container { + transform-style: preserve-3d; + transition: transform 0.5s; + transition-timing-function: ease-out; + transition-timing-function: cubic-bezier(0, 1.125, 0.335, 1.65); + height: @gridHeight*1.5; + + & > * { + position: absolute; + left: @gridWidth*2; + top: -1 * @gridHeight; + backface-visibility: hidden; + } + + .password-repeat { + transform: rotateX(180deg); + } + + &.repeat-field { + transform: rotateX(180deg); + } + } +} diff --git a/interface/client/styles/browserbar.import.less b/interface/client/styles/browserbar.import.less new file mode 100644 index 0000000..ef2c05b --- /dev/null +++ b/interface/client/styles/browserbar.import.less @@ -0,0 +1,364 @@ +.browser-bar { + .display(flex); + position: absolute; + top: @gridHeight * 1.5; + left: @widthSideBar; + right: 0; + z-index: 3; + height: @gridHeight * 2; + font-family: @sourceSansPro; + + button.icon { + padding: @gridHeight / 4 @gridWidth / 4; + + &:focus { + border: 0; + color: @colorLinkFocus; + } + } + + .app-bar { + position: relative; + .display(flex); + flex-grow: 1; + margin: @gridHeight / 4 @gridWidth / 4; + padding: @gridHeight / 4 @gridWidth / 4; + background: #fff; //#F6F6F6; + // border-radius: 3px; + // box-shadow: 0 2px 0 rgba(0, 0, 0, 0.25); + height: @gridHeight*1.7; + overflow: hidden; + + // ANIMATION + transition: height 0.25s, box-shadow 0.5s; + + > .dapp-info, + > button { + color: #6691c2; + position: relative; + padding-left: 0; + margin-top: 1px; + max-width: 33%; + height: 21px; + font-family: @sourceSansPro; + font-size: @fontSizeSmall; + font-weight: 500; + line-height: 21px; + white-space: nowrap; + margin-top: -1px; + + &.has-icon { + padding-left: @gridWidth * 0.84; + } + + &:focus { + border-bottom: 0; + } + + &.dapp-info { + .dapp-shorten-text; + } + + .app-icon { + position: absolute; + top: 0; + left: 0; + width: 21px; + height: 21px; + border-radius: 50%; + -webkit-user-drag: none; + user-drag: none; + } + + .connect-button { + float: left; + margin-right: 8px; + text-transform: uppercase; + } + .connect-button, + .dapp-info span { + line-height: 21px; + display: inline-block; + } + + span.no-accounts { + background-image: url(/images/anonymous-icon.png); + background-size: cover; + background-position: 50%; + width: 21px; + height: 21px; + display: inline-block; + border-radius: 50%; + } + } + + > form { + position: relative; + flex-grow: 1; + height: @gridHeight; + + .url-input { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + padding: 0; + margin: 0; + width: 100%; + max-width: none; + background: transparent; + border: none; + text-align: center; + color: @colorLinkBlur; + opacity: 0; + transform: translateX(-20px) translateZ(0); + font-size: 80%; + font-family: @sourceSansPro; + font-weight: 400; + transition: opacity 0.2s ease-in-out; + line-height: @gridHeight; + z-index: 10; + + &:focus { + color: @colorLinkActive; + opacity: 1; + } + + &:focus + .url-breadcrumb, + &:hover + .url-breadcrumb { + opacity: 0; + word-spacing: -4px; + } + } + + .url-breadcrumb { + color: lighten(@colorLinkBlur, 40%); + background-color: #fff; + opacity: 1; + font-size: 80%; + text-align: center; + font-weight: 400; + transition: opacity 0.2s ease-in-out, word-spacing 0.1s ease-in-out 0.1s; + line-height: @gridHeight; + height: @gridHeight; + overflow: hidden; + z-index: 1; + + span { + color: @colorLinkBlur; + } + } + + &:hover > .url-input { + opacity: 1; + transition: opacity 0.2s ease-in-out 0.1s; + } + + &:hover > .url-breadcrumb { + opacity: 0; + word-spacing: -3px; + transition: opacity 0.2s ease-in-out 0.1s, word-spacing 0.2s ease-in-out; + } + } + + div.dapp-info, + div.accounts, + div.url { + display: none; + position: absolute; + top: @gridHeight * 2; + left: 0; + right: 0; + bottom: 0; + padding: @gridHeight / 2 @gridWidth / 4 @gridHeight * 3; + margin: 0 @gridWidth / 4 0; + border-top: solid 1px #bdb6b6; + } + + div.accounts { + .message { + flex-grow: 1; + padding: @gridHeight / 2 @gridWidth / 2 0 0; + + h3 { + font-size: @fontSizeLarge; + text-transform: none; + color: #4a4a4a; + font-weight: 400; + + em { + font-weight: 700; + } + } + } + + .dapp-account-list { + min-width: @gridWidth * 10; + } + + .bar-actions { + display: flex; + justify-content: flex-end; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: @gridHeight * 3; + padding-top: @gridHeight; + + button { + display: inline-block; + font-size: 100%; + font-weight: 500; + text-transform: uppercase; + font-family: @sourceSansPro; + padding: @gridHeight / 4 @gridWidth / 2; + line-height: @gridHeight; + } + + button.cancel { + font-weight: 300; + } + } + } + } + + &.url-bar-transparent { + button.reload, + button.back { + display: none; + } + + button.icon-close { + width: @gridWidth; + padding: 0; + } + + .app-bar { + margin-left: @gridWidth / 2; + margin-right: @gridWidth / 2; + } + } +} +.linux .browser-bar { + top: 0; + &.url-bar-transparent { + top: @gridHeight * 1.5; + } +} + +.loading { + .url-input { + .color-pulse; + opacity: 1 !important; + } + .url-breadcrumb { + visibility: hidden; + word-spacing: -3px; + transition: word-spacing 0.5s ease-in-out; + } + .reload { + .rotating; + } +} + +.color-pulse { + animation-name: color-pulse; + animation-duration: 0.5s; + animation-iteration-count: infinite; + animation-timing-function: linear; + background: linear-gradient( + to left, + darken(@colorLinkActive, 30%) 0, + saturate(@colorLinkActive, 100%), + darken(@colorLinkActive, 30%) + ) !important; + background-size: 200px !important; + background-repeat: repeat-x; + -webkit-background-clip: text !important; + -webkit-text-fill-color: transparent; +} + +@keyframes color-pulse { + 0% { + transform: scale(0.992) translateZ(0); + opacity: 0.7; + background-position-x: 0px; + } + 50% { + transform: scale(1) translateZ(0); + opacity: 1; + } + 100% { + transform: scale(0.992) translateZ(0); + opacity: 0.7; + background-position-x: -200px; + } +} + +@colorBlockchain: #c3d825; + +.color-ping { + animation-name: color-ping; + animation-duration: 12s; + animation-iteration-count: infinite; + animation-timing-function: ease-out; + background-image: linear-gradient( + to top, + saturate(@colorLinkActive, 100%), + @colorGrayDark + ) !important; + background-size: 150px 150px; + background-position-y: 0; + + -webkit-background-clip: text !important; + -webkit-text-fill-color: transparent; +} + +@keyframes color-ping { + 0% { + transform: scale(1) translateZ(0); + background-position-y: 0; + } + 5% { + transform: scale(0.95) translateZ(0); + background-position-y: 30px; + } + 100% { + background-color: @colorGrayDark; + transform: scale(1) translateZ(0); + background-position-y: 150px; + } +} + +.rotating { + animation-name: rotating; + animation-duration: 0.5s; + animation-iteration-count: infinite; + animation-timing-function: linear; +} + +@keyframes rotating { + 0% { + transform: rotate(0deg) translate3d(0, 0, 0); + } + 100% { + transform: rotate(-180deg) translate3d(0, 1px, 0); + } +} + +@media screen and (max-width: 960px) { + .browser-bar .accounts { + width: 0; + text-overflow: clip; + padding-left: @gridWidth * 0.75; + } +} + +@media screen and (max-width: 800px) { + .browser-bar div.dapp-info { + width: 0; + text-overflow: clip; + } +} diff --git a/interface/client/styles/constants.import.less b/interface/client/styles/constants.import.less new file mode 100644 index 0000000..626d84b --- /dev/null +++ b/interface/client/styles/constants.import.less @@ -0,0 +1,25 @@ +@widthSideBar: 78px; + +@colorLinkActive: #4a90e2; +@colorLinkBlur: #494949; +@colorLinkFocus: lighten(@colorLinkBlur, 8%); + +@colorGrey: #666; + +@shadowStandard: -1px 0 4px rgba(0, 0, 0, 0.2); + +// FONTS +@sourceSansPro: 'Source Sans Pro', 'Helvetica Neue', 'Helvetica', Arial, + Sans-serif; +@fontSizeTiny: 8px; +@fontSizeSmall: 12px; +@fontSizeNormal: 14px; +@fontSizeLarge: 18px; + +// Platform specifics +// Mac OSX +@colorOSBackgroundFocus: #d2d2d2; +@colorOSBackgroundBlur: #f6f6f6; + +// Windows +// @colorOSBackgroundFocus windows F0F0F0 diff --git a/interface/client/styles/elements.import.less b/interface/client/styles/elements.import.less new file mode 100644 index 0000000..6f21ab5 --- /dev/null +++ b/interface/client/styles/elements.import.less @@ -0,0 +1,41 @@ +.red { + color: @colorError; +} +.gree { + color: @colorGreen; +} +.blue { + color: @colorBlue; +} + +img { + transition: opacity @animationSpeed / 2; + + &.loading { + opacity: 0; + } +} + +ul.no-bullets { + margin: 0; + padding: 0; + list-style: none; + word-wrap: break-word; + + li { + margin: 0; + margin-bottom: @defaultMargin / 2; + + strong { + font-weight: 400; + } + } +} + +.danger { + display: inline-block; + padding: 1px 2px; + border-radius: 3px; + color: @colorWhite; + background-color: @colorError; +} diff --git a/interface/client/styles/importAccount.import.less b/interface/client/styles/importAccount.import.less new file mode 100644 index 0000000..3de4a63 --- /dev/null +++ b/interface/client/styles/importAccount.import.less @@ -0,0 +1,303 @@ +.import-account { + display: flex; + flex-direction: column; + height: 100%; + position: relative; + // background: lighten(@colorOSBackgroundFocus, 10%); + + .main-content { + z-index: 1; + flex: 1 100%; + + h1 { + margin: @gridHeight*2 0 @gridHeight / 2; + } + + .description { + font-weight: 500; + padding-bottom: @gridHeight; + } + + .col { + padding: 0; + } + + button, + a.button { + display: block; + text-transform: uppercase; + font-weight: 500; + color: @colorLinkActive; + } + + p { + margin: 0; + padding: @gridHeight 0; + font-size: 90%; + } + + .onboarding-start { + padding: @gridHeight @gridWidth @gridHeight @gridWidth * 10; + background-image: url('/images/onboarding-logo-metal.png'); + background-repeat: no-repeat; + background-position-y: @gridHeight*4; + background-size: 255px 257px; + + button, + a.button { + font-size: 110%; + text-align: left; + } + } + + .dropable { + display: block; + padding: @gridHeight*4 @gridWidth; + margin: @gridHeight 0; + background: lighten(@colorLinkActive, 30%); + border: dashed 3px @colorLinkActive; + border-radius: 3px; + text-align: center; + font-size: 150%; + color: @colorLinkActive; + + &.active { + transform: scale(1.05) !important; + } + } + + .dapp-block-button { + margin: 0 auto; + background-color: transparent; + border: solid 1px @colorLinkActive; + font-size: 80%; + } + + input { + background-color: transparent; + border-bottom: dashed 1px; + } + + input.name { + text-align: center; + margin: @gridHeight / 2 0 @gridHeight; + } + + input[type='checkbox'] { + margin-left: 14px; + } + + input[type='checkbox'] + label { + position: relative; + top: -7px; + left: 9px; + opacity: 0.9; + } + + h6 { + opacity: 0.2; + margin: 0 0 @gridHeight / 2; + } + + .footer-buttons { + position: absolute; + bottom: @gridHeight*5; + + button { + position: absolute; + } + } + .right-align { + right: @gridWidth * 2; + } + + .col-left { + padding-right: @gridWidth; + p { + padding-bottom: 0; + } + } + } + + footer { + z-index: 2; + flex: 0 @gridHeight * 4; + height: @gridHeight * 4; + padding: @gridHeight / 2 @gridWidth / 4; + display: flex; + flex-flow: row wrap; + + progress { + width: 100%; + height: 2px; + background: transparent; + + &.stateBar { + position: absolute; + left: 8px; + right: 8px; + bottom: 45px; + width: auto; + opacity: 0.15; + + &::-webkit-progress-value { + background: #000; + } + } + } + + button { + position: relative; + top: -3px; + margin: 0 auto; + text-transform: uppercase; + font-weight: 500; + text-align: center; + display: block; + // width: 100%; + color: @colorLinkActive; + } + + .status { + flex: 1; + } + + div { + font-size: 80%; + font-weight: 500; + opacity: 0.5; + padding: 0 @gridWidth / 2; + } + } + + /* Screen transitions */ + + .onboarding-section { + padding: @gridHeight @gridWidth; + opacity: 0; + z-index: 0; + transition: opacity 0.2s ease-in-out; + position: absolute; + height: 100%; + width: 100%; + perspective: 500px; + + h4 { + margin-bottom: 0; + } + } + + .onboarding-start { + transition: opacity 0.8s, background-position-x 1.2s ease-in-out; + background-position-x: -200px; + p { + transform: translateX(300px); + transition: transform 0.6s ease-in-out; + } + } + + &.active-start .onboarding-start { + display: block; + opacity: 1; + background-position-x: @gridWidth; + z-index: 100; + transition-delay: 0.3s; + p { + transform: translateX(0); + transition-delay: 0.9s; + } + } + + .onboarding-import-account { + opacity: 0; + z-index: 0; + transition-duration: 0s; + .col-6.col-left { + transform: scale(0.9) translateZ(-10px); + transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + } + } + + .dapp-identicon.dapp-icon-loading { + position: relative; + margin-left: -32px; + left: 50%; + } + + .onboarding-account .col-deposit { + text-align: center; + } + + .onboarding-password { + transition: none; + .col-6 { + transition: none; + transform: translateX(0); + } + .col-6.col-left { + opacity: 0; + transform: translateX(-100px); + } + } + + .onboarding-testnet, + .onboarding-account { + transition: opacity 0.4s ease-in-out; + + .col-6 { + transition: transform 0.2s ease-in-out, opacity 0.2s; + transform: translateX(0); + } + .col-6.col-left { + opacity: 0; + transform: translateX(-100px); + } + + .dapp-identicon.dapp-icon-loading { + margin-left: 0 auto; + } + + .you { + position: absolute; + font-weight: 600; + color: @colorLinkActive; + border: dashed @colorLinkActive 2px; + width: @gridWidth*2; + height: @gridWidth*2; + border-radius: 50%; + line-height: 60px; + top: 0; + left: @gridWidth*3; + z-index: -1; + } + + h6.address { + .allowSelection; + } + } + + &.active-import-account .onboarding-import-account, + &.active-password .onboarding-password, + &.active-testnet .onboarding-testnet, + &.active-account .onboarding-account { + display: block; + opacity: 1; + z-index: 100; + transition-delay: 0.1s; + .col-6 { + opacity: 1; + transform: translateX(0); + transition-delay: 0.2s; + } + .dapp-identicon { + transform: translateX(0); + } + } + + .onboarding-testnet, + &.active-account .onboarding-account { + transition-delay: 0; + transition-duration: 0; + transition: none; + } +} diff --git a/interface/client/styles/layout.import.less b/interface/client/styles/layout.import.less new file mode 100644 index 0000000..0cf7c18 --- /dev/null +++ b/interface/client/styles/layout.import.less @@ -0,0 +1,197 @@ +// Platform specifics +// Mac OSX +@colorOSBackgroundFocus: #f1f1f1; +@colorOSBackgroundBlur: #f6f6f6; + +@colorWinBackgroundFocus: #f0f0f0; +@colorWinBackgroundBlur: #f0f0f0; + +// WINDOWS +.win32 { +} + +// LINUX +// use only to solve OS conflicts +.linux { +} + +// MAC +.darwin, +.linux { + body { + background: @colorOSBackgroundFocus; + + &.app-blur { + background: @colorOSBackgroundBlur; + } + } + + .darwin { + aside { + top: @gridHeight * 2; + height: calc(100% - @gridHeight * 2); + } + + div.browser-bar { + top: @gridHeight * 1.5; + } + + .node-info { + top: @gridHeight; + } + } +} + +body, +html { + height: 100%; + padding: 0; + margin: 0; + overflow: hidden; + background: @colorWinBackgroundFocus; + + &.app-blur { + background: @colorWinBackgroundBlur; + } + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +h1, +h2, +h3, +p { + cursor: default; +} +pre { + .allowSelection; + cursor: text; +} +a h1, +a h2, +a h3, +a p, +button h1, +button h2, +button h3, +button p { + cursor: pointer; +} + +main { + z-index: 1; + position: absolute; + right: 0; + left: @widthSideBar; + top: 0; + bottom: 0; +} + +.drag-bar { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 30px; + -webkit-user-select: none; + -webkit-app-region: drag; +} + +// Fading Mist interface when sendTransactionConfirmationPopup is shown. +html { + &.has-blur-overlay { + pointer-events: none; + opacity: 0.7; + body { + -webkit-filter: blur(3px); + transform: scale(1.001) translate3d(0, 0, 0); + } + } +} + +.webview { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-left: 1px solid #e2e2e2; + background: #fff; + overflow: hidden; + opacity: 1; + z-index: 10; + + &.hidden { + z-index: 0; + } + + &.app-bar-transparent webview { + top: 0; + margin-top: 0; + } +} + +webview { + position: absolute; + top: @gridHeight * 1.5; + left: 0; + right: 0; + bottom: 0; + overflow: hidden; + margin-top: @gridHeight*2; + border-top: solid 1px rgba(0, 0, 0, 0.1); +} +.linux webview { + top: 0; +} + +// Scrollbars +// Reference: https://gist.github.com/devinrhode2/2573411 +aside.sidebar { + ::-webkit-scrollbar { + width: 7px; + background-color: rgba(0, 0, 0, 0); + -webkit-border-radius: 100px; + } + ::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.09); + } + + ::-webkit-scrollbar-thumb:vertical { + background: rgba(0, 0, 0, 0.5); + -webkit-border-radius: 100px; + } + ::-webkit-scrollbar-thumb:vertical:active { + background: rgba(0, 0, 0, 0.61); + -webkit-border-radius: 100px; + background-clip: padding-box; + border: 2px solid rgba(0, 0, 0, 0); + } + + ::-webkit-scrollbar { + width: 10px; + } + + ::-webkit-scrollbar-thumb:vertical { + background-clip: padding-box; + border: 2px solid rgba(0, 0, 0, 0); + min-height: 30px; + } + + .submenu-container { + ::-webkit-scrollbar-thumb:vertical { + background: rgba(255, 255, 255, 0.5); + border: 2px solid rgba(0, 0, 0, 0); + background-clip: padding-box; + } + ::-webkit-scrollbar-thumb:vertical:active { + background: rgba(255, 255, 255, 0.61); + border: 2px solid rgba(0, 0, 0, 0); + background-clip: padding-box; + } + } +} diff --git a/interface/client/styles/menu.import.less b/interface/client/styles/menu.import.less new file mode 100644 index 0000000..378c6f6 --- /dev/null +++ b/interface/client/styles/menu.import.less @@ -0,0 +1,335 @@ +.gradient-tip { + content: ''; + display: block; + width: 100%; + height: @gridHeight * 0.75; + left: 0px; + position: absolute; + pointer-events: none; +} + +.sidePadding { + padding-left: 11px; + padding-right: 11px; +} + +// OS-specific styles +html.darwin aside.sidebar { + top: @gridHeight; + + &::after { + top: @gridHeight; + } + nav { + margin-top: @gridHeight; + } +} + +aside.sidebar { + display: flex; + flex-flow: column nowrap; + justify-content: space-between; + + z-index: 4; + position: absolute; + top: @gridHeight / 2; + left: 0; + bottom: 0; + width: @widthSideBar; + + &::after { + .gradient-tip(); + top: @gridHeight / 2; + height: 8px; + background-image: linear-gradient( + to top, + rgba(241, 241, 241, 0) 0%, + rgba(241, 241, 241, 1) 100% + ); + } + + nav { + position: relative; + margin-top: @gridHeight / 2; + padding: 0 12px 0; + overflow: hidden; + min-height: 0; + &:hover { + overflow-y: auto; + } + + > ul { + margin: 6px 0; + padding: 0; + width: 54px; + + > li { + overflow: hidden; + margin-bottom: 14px; + transition-delay: 200ms; + + // draggable LI + &.ui-sortable-helper { + transform: scale(1.1); + .submenu-container { + display: none; + } + } + + &:hover { + .submenu-container { + opacity: 1; + visibility: visible; + } + } + + &.selected, + &:active, + &:hover, + &:focus { + button.main { + opacity: 1; + } + } + button.main { + height: 55px; + width: 54px; + display: block; + opacity: 0.6; + transition: 100ms opacity linear; + + &:focus { + outline: 0; + border: none; + } + + .icon-globe { + font-size: 32px; + text-align: center; + display: block; + background-color: #fff; + padding-top: 10px; + } + + img, + .icon-globe { + width: 54px; + height: 54px; + -webkit-mask-image: url('icons/mask-icon.svg'); + -webkit-mask-size: cover; + } + } + } + } + + .submenu-container { + width: 185px; + position: fixed; + left: 90px; + top: 120px; + border-radius: 5px; + z-index: 1000; + visibility: hidden; + opacity: 0; + cursor: default; + + transition: 150ms linear all, 1ms linear top; + transition-delay: 200ms; + transform: translateY(-11px); + // backdrop-filter: blur(0); + + &::before { + @tipSize: 8px; + content: ''; + margin-left: -@tipSize; + margin-top: 19px + 11px; + display: block; + position: absolute; + width: 0px; + height: @tipSize * 2.25; + border: 0px solid transparent; + border-width: @tipSize; + border-left: 0; + border-right-color: rgba(0, 0, 0, 0.78); + } + + button { + &:active, + &:focus { + transform: none; + border: none; + } + } + + section { + padding: 8px 0 0; + background-color: rgba(0, 0, 0, 0.78); + // backdrop-filter: blur(5px); + width: 100%; + border-radius: 5px; + color: #fff; + position: relative; + + header { + .sidePadding(); + padding-bottom: 11px; + } + span { + font-weight: 400; + } + a, + button { + color: #fff; + } + .badge { + font-size: 11px; + } + .remove-tab { + color: #a6a6a6; + position: absolute; + right: 5px; + top: 4px; + width: 14px; + &:hover { + color: #fff; + } + } + + .accounts { + margin-top: 11px; + button { + font-size: 12px; + font-weight: 300; + text-transform: uppercase; + width: 100%; + } + .connect { + background-color: #4c92e6; + border-radius: 4px; + padding: 3px 0; + } + .display { + @identiconHeight: 17px; + text-align: left; + line-height: @identiconHeight; + + .dapp-identicon-container { + float: right; + height: @identiconHeight; + } + + .dapp-identicon { + margin-right: 0px; + width: @identiconHeight; + height: @identiconHeight; + &:not(:last-child) { + margin-right: 4px; + } + } + } + } + } + + .sub-menu { + margin: 6px 0; + padding: 0; + border-top: 1px solid rgba(255, 255, 255, 0.2); + overflow-y: auto; + overflow-x: hidden; + padding-bottom: 0.1em; + margin-top: 2px; + margin-bottom: 0; + li { + opacity: 1; + font-weight: normal; + font-size: 14px; + margin-bottom: 0; + button { + padding: 8px 0 6px; + .sidePadding(); + box-sizing: border-box; + width: 100%; + text-align: left; + background-color: rgba(255, 255, 255, 0); + transition: 150ms linear background-color; + + margin: 5px 0; + display: -webkit-box; + -webkit-line-clamp: 2; // 2 lines max + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + &:hover { + background-color: rgba(255, 255, 255, 0.2); + } + .badge { + display: block; + opacity: 0.8; + } + } + } + } + } + } + + .node-info { + position: relative; + cursor: default; + + &::after { + .gradient-tip(); + height: 20px; + top: -(20px - 1); + background-image: linear-gradient( + to bottom, + rgba(241, 241, 241, 0) 0%, + rgba(241, 241, 241, 1) 100% + ); + } + + display: flex; + flex-flow: row wrap; + flex-shrink: 0; + padding: 8px; + font-size: 0.9em; + color: @colorTextSecondary; + + div, + span { + padding: @gridHeight / 2 1px; + flex: 1; + text-align: center; + } + + i { + display: block; + margin-bottom: 2px; + } + + progress { + flex: 1 100%; + } + + .mining-indicator { + flex: 3; + } + + .block-number { + flex: 2; + white-space: nowrap; + } + + .test-chain { + flex: 1 100%; + padding: 1px 5px 2px; + } + } +} + +.app-blur aside.newsidebar nav::after { + background-image: linear-gradient( + to bottom, + rgba(246, 246, 246, 0) 0%, + rgba(246, 246, 246, 1) 100% + ); +} diff --git a/interface/client/styles/mixins.import.less b/interface/client/styles/mixins.import.less new file mode 100644 index 0000000..7d3591f --- /dev/null +++ b/interface/client/styles/mixins.import.less @@ -0,0 +1,17 @@ +.allowSelection { + -webkit-touch-callout: initial; + -webkit-user-select: initial; + -khtml-user-select: initial; + -moz-user-select: initial; + -ms-user-select: initial; + user-select: initial; +} + +.disallowSelection { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} diff --git a/interface/client/styles/networkIndicator.import.less b/interface/client/styles/networkIndicator.import.less new file mode 100644 index 0000000..b469f69 --- /dev/null +++ b/interface/client/styles/networkIndicator.import.less @@ -0,0 +1,27 @@ +// Applies to both onboarding and splash screen +.network-indicator { + position: absolute; + top: 10px; + right: 10px; + left: 10px; + text-align: right; + font-weight: 600; + font-size: 80%; + opacity: 0.8; + color: @colorGrey; + text-transform: uppercase; +} + +// Applies only to the splash screen +.splash-screen .network-indicator .unknown { + position: absolute; + top: 155px; + text-align: center; + left: 10px; + right: 10px; + font-size: 110%; + opacity: 0.8; + font-weight: normal; + text-transform: none; + color: #fff; +} diff --git a/interface/client/styles/popupWindows.import.less b/interface/client/styles/popupWindows.import.less new file mode 100644 index 0000000..6f07dd5 --- /dev/null +++ b/interface/client/styles/popupWindows.import.less @@ -0,0 +1,622 @@ +@-webkit-keyframes slideInLeft { + from { + transform: translate3d(50%, 0, 0) rotate(45deg); + opacity: 0; + } + to { + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@-webkit-keyframes slideInRight { + from { + transform: translate3d(-50%, 0, 0) rotate(-45deg); + opacity: 0; + } + to { + transform: none; + opacity: 1; + } +} + +@-webkit-keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.popup-windows { + text-align: center; + height: 100vh; + + a, + button { + color: @colorLinkActive; + } + a:focus { + color: @colorLinkFocus; + } + + h3 { + color: @colorGrayDark; + a { + float: right; + font-weight: 400; + } + } + img.left-overlay { + position: relative; + top: -40px; + left: -160%; + width: 300%; + z-index: 1; + } + + footer { + position: fixed; + bottom: 0; + left: 0; + right: 0; + padding: 0 @gridHeight; + padding-top: @gridHeight * 3; + background: linear-gradient(transparent 0%, @colorGrayLight 35%); + + &.dapp-small { + background: linear-gradient(transparent 50%, @colorGrayLight 70%); + } + } + + .info.dapp-error { + color: @colorError; + font-weight: 600; + } + + &.update-available { + -webkit-user-select: auto; + user-select: auto; + + .text { + text-align: left; + } + h1 { + font-size: 200%; + margin-bottom: 20px; + + &.no-update { + font-size: 180%; + } + } + } + &.tx-info { + .container { + overflow: auto; + height: 80vh; + padding-bottom: 120px; + } + + .transaction-parties { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + margin: 0 @gridWidth; + + > div { + // flex: 1 1 auto; + color: @colorTextSecondary; + position: relative; + } + + div.connection { + padding: @gridHeight @gridWidth / 2; + } + + div.amount, + div.function-signature { + flex: 1 50%; + } + + // amount + div.amount { + position: relative; + margin-top: -30px; + height: 40px; + font-size: 1.5em; + color: darken(@colorTextSecondary, 8%); + border-bottom: 1px solid @colorTextSecondary; + &:after { + content: ''; + position: absolute; + bottom: -5px; + right: 0; + border: 5px solid @colorTextSecondary; + border-color: transparent @colorTextSecondary @colorTextSecondary + transparent; + .rotate(-45deg); + } + .unit { + font-size: 0.6em; + font-weight: 400; + } + .execute-function { + display: block; + position: absolute; + bottom: -30px; + left: 0; + right: 0; + font-size: 0.6em; + text-align: center; + font-weight: 600; + } + } + .function-signature { + font-weight: 400; + font-size: 1.5em; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + text-transform: uppercase; + max-width: @gridWidth * 10; + + &.has-signature { + text-transform: none; + } + } + } + table, + .data, + .parameters, + .fees, + .info { + width: 420px; + margin: @defaultMargin*2 auto; + } + table { + td:nth-child(1) { + text-align: left; + } + td:nth-child(2) { + text-align: right; + font-weight: 400; + } + } + + // Parameters + .fees, + .parameters { + font-size: 0.9em; + text-align: left; + ul, + ol { + counter-reset: item; + padding: 0; + list-style-type: none; + list-style-position: inside; + li { + display: flex; + min-height: @gridHeight * 2; + align-items: center; + + .allowSelection; + font-weight: 200; + transition: background 0.5s ease-out; + + & > div { + padding: 0 @gridWidth / 4; + } + .value { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + .icon { + position: relative; + top: 1px; + } + &:hover strong { + word-break: break-all; + } + } + .type { + text-align: right; + max-width: @gridWidth * 10; + } + + &:hover { + background-color: #fff; + transition: background 0.1s ease-in; + } + } + + ::selection { + color: #fff; + background: @colorLink; + } + } + + ol li::before { + counter-increment: item; + content: counter(item); + opacity: 0.5; + color: @colorGrayDark; + font-weight: 400; + } + } + + .overlap-icon { + position: absolute; + top: 34px; + font-size: 18px; + text-align: center; + color: #fff; + width: @gridWidth*2; + opacity: 0.75; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.5); + } + .circle-icon { + display: inline-block; + background-color: @colorGrayLight; + .border-radius(50%); + font-size: 33px; + padding: @defaultMargin; + // + span { + // display: inline-block; + // } + } + .provided-gas { + display: inline; + width: 70px; + padding: 0; + margin: 0; + color: @colorLink; + background-color: transparent; + border: 0; + text-align: right; + border-bottom: 1px dotted @colorLink; + &:focus { + outline: 0; + } + } + input[type='password'] { + width: @gridWidth * 12; + } + .data, + .info { + text-align: left; + padding: 0 @defaultMargin / 2; + } + .data { + font-size: 0.9em; + pre { + margin: 0 -@defaultMargin; + overflow: auto; + height: 90px; + background-color: @colorGrayLight; //lighten(@colorGray, 10%); + color: @colorTextPrimary; + span.zero { + color: fadeout(@colorTextSecondary, 30%); + } + span.function { + font-weight: 600; + } + } + } + } + &.request-account { + h1 { + margin-bottom: 20px; + } + .fields-container { + // addresses + > div:nth-child(odd) { + position: relative; + padding: 0 @defaultMargin*2; + font-weight: 400; + } + > div:nth-child(1) { + .overlap-icon { + right: @defaultMargin * 1.25; + } + } + > div:nth-child(3) { + .overlap-icon { + left: @defaultMargin * 1; + } + } + // amount + > div.amount { + position: relative; + margin-top: -30px; + height: 40px; + width: @defaultMargin * 10; + font-size: 1.5em; + color: darken(@colorTextSecondary, 8%); + border-bottom: 1px solid @colorTextSecondary; + + &:after { + content: ''; + position: absolute; + bottom: -5px; + right: 0; + border: 5px solid @colorTextSecondary; + border-color: transparent @colorTextSecondary @colorTextSecondary + transparent; + .rotate(-45deg); + } + + .unit { + font-size: 0.6em; + font-weight: 400; + } + } + } + + table, + .data, + .info { + width: 420px; + margin: @defaultMargin*2 auto; + } + table { + td:nth-child(1) { + text-align: left; + } + td:nth-child(2) { + text-align: right; + font-weight: 400; + } + } + + .overlap-icon { + position: absolute; + top: 20px; + font-size: 20px; + } + .circle-icon { + display: inline-block; + background-color: @colorGrayLight; + .border-radius(50%); + font-size: 33px; + padding: @defaultMargin; + + // + span { + // display: inline-block; + // } + } + + .provided-gas { + display: inline; + width: 70px; + padding: 0; + margin: 0; + color: @colorLink; + background-color: transparent; + border: 0; + text-align: right; + border-bottom: 1px dotted @colorLink; + + &:focus { + outline: 0; + } + } + + .show-password-container { + width: 300px; + margin: 0 auto 0; + padding: 12px 0 0; + text-align: left; + input[type='checkbox'] { + margin-left: 16px; + } + label { + position: relative; + top: -7px; + left: 6px; + opacity: 0.9; + font-size: 14px; + } + } + } + &.connect-account { + text-align: left; + box-sizing: border-box; + margin: 0 auto; + padding: 0 60px; + form { + display: -webkit-flex; + display: flex; + flex-direction: column; + align-content: space-between; + height: 100vh; + + > * { + flex: 0; + } + } + p strong { + font-weight: 400; + } + .account-dapp-user-container { + display: -webkit-flex; + display: flex; + height: 64px; + justify-content: center; + align-items: center; + margin: 30px 0 15px; + flex: 0 64px; + } + .account-dapp-user { + margin: 0 5px; + position: relative; + width: 120px; + height: 64px; + & > * { + position: absolute; + top: 0; + display: inline-block; + width: 64px; + height: 64px; + border-radius: 50%; + &.is-empty { + background-color: #6e6c6f; + border-radius: 50%; + i { + color: #fff; + display: block; + text-align: center; + line-height: 64px; + font-size: 2.8em; + } + } + &.no-account { + background-image: url(/images/anonymous-icon.png); + background-size: cover; + background-position: 50%; + } + } + .user-icon, + .simptip-position-left { + z-index: 2; + left: 0; + animation: 0.7s cubic-bezier(0, 0, 0.13, 1) slideInLeft; + &:first-child { + left: 0px; + } + &:nth-of-type(2) { + left: 5px; + } + &:nth-of-type(3) { + left: 10px; + } + &:nth-of-type(4) { + left: 15px; + } + &:nth-of-type(5) { + left: 20px; + } + &:nth-of-type(6) { + left: 25px; + } + } + .app-icon { + z-index: 1; + left: 55px; + animation: 0.7s cubic-bezier(0, 0, 0.13, 1) slideInRight; + } + } + .dapp-account-list { + flex-grow: 5; + position: relative; + overflow: auto; + padding: 0; + margin: 0; + &::after { + position: fixed; + content: ''; + display: block; + bottom: 130px; + width: 100%; + height: @gridHeight * 1.5; + pointer-events: none; + background: -webkit-linear-gradient( + top, + rgba(241, 241, 241, 0), + rgba(241, 241, 241, 1) + ); + } + li:last-child { + margin-bottom: 25px; + } + } + .create-account-icon { + background-color: @colorLinkActive; + box-shadow: none; + &:after { + color: #fff; + content: '+'; + display: block; + text-align: center; + line-height: 32px; + font-size: 1.7em; + font-weight: 400; + } + } + .checkbox-container { + display: flex; + flex: 0 50px; + padding: 1em 0; + input { + margin-right: 6px; + } + label { + color: @colorLinkActive; + font-weight: 500; + } + } + .dapp-modal-buttons { + flex: 0 62px; + } + .dapp-modal-buttons, + .dapp-modal-buttons button:last-of-type { + margin-right: 0; + } + span.account-address, + span.dapp-url { + animation: 0.9s cubic-bezier(0.74, 0, 1, 0.29) fadeIn; + display: inline-block; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + width: 100px; + font-size: 14px; + color: #aeaeae; + } + + .data, + .info { + text-align: left; + padding: 0 @defaultMargin / 2; + position: relative; + .toggle-panel { + position: absolute; + right: 0; + top: 0; + font-weight: 500; + font-size: 0.8em; + } + } + .data { + font-size: 0.9em; + + pre { + margin: 0 -@defaultMargin; + overflow: auto; + height: 90px; + background-color: @colorGrayLight; //lighten(@colorGray, 10%); + color: @colorTextPrimary; + + span.zero { + color: fadeout(@colorTextSecondary, 30%); + } + span.function { + font-weight: 600; + } + } + } + } +} + +body.app-blur + .popup-windows.connect-account + .cards-container + .switch-card + ul::after { + background: -webkit-linear-gradient( + top, + rgba(246, 246, 246, 0), + rgba(246, 246, 246, 1) + ); +} diff --git a/interface/client/styles/splashScreen.import.less b/interface/client/styles/splashScreen.import.less new file mode 100644 index 0000000..d9ae26b --- /dev/null +++ b/interface/client/styles/splashScreen.import.less @@ -0,0 +1,184 @@ +@font-face { + font-family: 'Source Sans Pro'; + src: url('fonts/SourceSansPro.otf'); + font-weight: 500; + font-style: normal; +} + +.splash-screen { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + color: #fff; + text-align: center; + font-family: 'Source Sans Pro', 'Helvetica Neue', 'Helvetica', verdana, arial; + overflow: hidden; + + background-size: cover; + background-position: 50% 50%; + -webkit-app-region: drag; + + &.wallet { + background-image: url('/images/bg-homestead.jpg'); + + h1 { + color: #fff; + } + button.start-app, + button.retry-connection { + color: #bcd3e6; + &:hover { + color: darken(#bcd3e6, 5%); + } + } + button.close { + color: rgba(0, 0, 0, 0.3); + + &:hover { + color: rgba(0, 0, 0, 0.8); + } + } + } + &.mist { + background-image: url('/images/bg-metropolis.jpg'); + + h1 { + color: #152f58; + text-shadow: 0 1px 5px rgba(255, 255, 255, 0.75); + } + + .network-indicator { + color: #fff; + opacity: 0.9; + .unknown { + color: #152f58; + text-shadow: 0 1px 5px rgba(255, 255, 255, 0.75); + } + } + } + + h1, + small { + cursor: default; + } + + button { + -webkit-app-region: no-drag; + z-index: 3; + position: absolute; + color: #fff; + background: none; + border: 0; + outline: 0; + padding: @defaultMargin / 2; + font-size: 0.8em; + } + button:active { + transform: scale(0.95); + } + + /* Close button */ + button.close { + top: 0; + right: 3px; + font-size: 20px; + color: rgba(255, 255, 255, 0.3); + } + button.close:hover { + color: rgba(255, 255, 255, 0.8); + } + /* start app button */ + button.start-app, + button.retry-connection { + bottom: 10px; + right: 0; + left: 0; + width: 100%; + margin: 0; + padding: 0; + text-align: center; + color: #4a90e2; + text-transform: uppercase; + font-family: 'Source Sans Pro', 'Helvetica Neue', 'Helvetica', verdana, + arial; + font-size: 1em; + font-weight: bold; + } + button.start-app:hover, + button.retry-connection:hover { + color: #2a6ed0; + } + + img { + margin-top: 7px; + width: 110px; + transition: width 0.5s ease-in-out; + } + &.small img { + width: 80px; + } + img.shadow { + box-shadow: 0 0 15px rgba(0, 0, 0, 0.4); + border-radius: 50%; + } + h1 { + margin-top: 10px; + font-size: 18px; + font-weight: 400; + /*text-shadow: 0 1px 5px rgba(0,0,0,0.6);*/ + -webkit-user-select: none; + } + &.small h1 { + margin-top: 20px; + } + small { + display: inline-block; + margin-top: 2px; + opacity: 0.6; + line-height: 1.3em; + cursor: text; + -webkit-app-region: no-drag; + -webkit-user-select: initial; + } + + /* PROGRESSBAR */ + progress { + position: absolute; + bottom: 35px; + left: 10px; + right: 10px; + -webkit-appearance: none; + appearance: none; + width: auto; + height: 10px; + opacity: 0.8; + } + + progress[value]::-webkit-progress-bar { + background-color: rgba(255, 255, 255, 0.2); + border-radius: 2px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset; + } + + progress.wallet::-webkit-progress-value { + background-image: -webkit-linear-gradient(left, #dccab6, #fff); + } + progress.mist::-webkit-progress-value { + background-image: -webkit-linear-gradient(left, #3185cc, #ada1e2); + } + progress::-webkit-progress-value { + opacity: 0.7; + border-radius: 2px; + box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.3); + } + + progress.state { + opacity: 0.3; + } + + progress.state[value]::-webkit-progress-bar { + background: transparent; + } +} diff --git a/interface/client/styles/styles.less b/interface/client/styles/styles.less new file mode 100644 index 0000000..d29c281 --- /dev/null +++ b/interface/client/styles/styles.less @@ -0,0 +1,14 @@ +// libs +@import '{ethereum:dapp-styles}/dapp-styles.less'; + +@import 'constants.import.less'; +@import 'mixins.import.less'; +@import 'elements.import.less'; +@import 'layout.import.less'; +@import 'networkIndicator.import.less'; +@import 'splashScreen.import.less'; +@import 'importAccount.import.less'; +@import 'menu.import.less'; +@import 'browserbar.import.less'; +@import 'popupWindows.import.less'; +@import 'animations.import.less'; diff --git a/interface/client/templates/elements/img.html b/interface/client/templates/elements/img.html new file mode 100644 index 0000000..b5faeea --- /dev/null +++ b/interface/client/templates/elements/img.html @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/interface/client/templates/elements/img.js b/interface/client/templates/elements/img.js new file mode 100644 index 0000000..61bbe0b --- /dev/null +++ b/interface/client/templates/elements/img.js @@ -0,0 +1,33 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The img template + +@class [template] elements_img +@constructor +*/ + +Template['elements_img'].helpers({ + /** + This helper will preload the image, and then inject it later after its loaded + + @method (preload) + */ + preload: function() { + var template = Template.instance(), + data = this, + img = new Image(); + + TemplateVar.set('loading', true); + + img.onload = function() { + TemplateVar.set(template, 'loading', false); + TemplateVar.set(template, 'src', data.src); + }; + img.src = data.src; + } +}); diff --git a/interface/client/templates/elements/networkIndicator.html b/interface/client/templates/elements/networkIndicator.html new file mode 100644 index 0000000..20e47a6 --- /dev/null +++ b/interface/client/templates/elements/networkIndicator.html @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/interface/client/templates/elements/networkIndicator.js b/interface/client/templates/elements/networkIndicator.js new file mode 100644 index 0000000..3268d4d --- /dev/null +++ b/interface/client/templates/elements/networkIndicator.js @@ -0,0 +1,78 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The networkIndicator template + +@class [template] elements_networkIndicator +@constructor +*/ + +/** +Check network type. + +@method checkNetworkType +*/ +var checkNetworkType = function(template) { + console.trace('Check network type...'); + + try { + web3.eth.getBlock(0, function(e, res) { + console.trace('Get block 0', e, res); + + if (e) { + console.error('Got error fetching block 0', e); + } else { + TemplateVar.set( + template, + 'network', + Helpers.detectNetwork(res.hash).type + ); + TemplateVar.set( + template, + 'networkName', + Helpers.detectNetwork(res.hash).name + ); + } + }); + } catch (err) { + console.error('Unable to get block 0', err); + } +}; + +Template['elements_networkIndicator'].onRendered(function() { + var template = this; + + TemplateVar.set(template, 'network', 'unknown'); + + checkNetworkType(template); + + ipc.on('uiAction_nodeStatus', function(e, status) { + console.trace('Node status', status); + + switch (status) { + case 'starting': + case 'stopping': + case 'connected': + console.debug('Node status changing, reset network type indicator'); + TemplateVar.set(template, 'network', 'unknown'); + break; + } + }); + + ipc.on('uiAction_nodeSyncStatus', function(e, status, data) { + console.trace('Node sync status', status); + + if ( + 'inProgress' === status && + TemplateVar.get(template, 'network') === 'unknown' + ) { + console.debug('Node syncing, re-check network type.'); + + checkNetworkType(template); + } + }); +}); diff --git a/interface/client/templates/elements/nodeInfo.html b/interface/client/templates/elements/nodeInfo.html new file mode 100644 index 0000000..6a259b4 --- /dev/null +++ b/interface/client/templates/elements/nodeInfo.html @@ -0,0 +1,34 @@ + diff --git a/interface/client/templates/elements/nodeInfo.js b/interface/client/templates/elements/nodeInfo.js new file mode 100644 index 0000000..5f0b04a --- /dev/null +++ b/interface/client/templates/elements/nodeInfo.js @@ -0,0 +1,155 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +Update the peercount + +@method getPeerCount +*/ +var getPeerCount = function(template) { + web3.net.getPeerCount(function(e, res) { + if (!e) TemplateVar.set(template, 'peerCount', res); + }); +}; + +/** +Update the mining hashrate + +@method getMining +*/ +var getMining = function(template) { + web3.eth.getMining(function(e, res) { + if (!e && res) { + web3.eth.getHashrate(function(e, res) { + if (!e) { + TemplateVar.set( + template, + 'mining', + numeral(res / 1000).format('0,0.0') + ); + } + }); + } else { + TemplateVar.set(template, 'mining', false); + } + }); +}; + +/** +The main template + +@class [template] elements_nodeInfo +@constructor +*/ + +Template['elements_nodeInfo'].onCreated(function() { + var template = this; + + // CHECK FOR NETWORK + web3.eth.getBlock(0, function(e, res) { + if (!e) { + const network = Helpers.detectNetwork(res.hash); + TemplateVar.set(template, 'network', network.type); + TemplateVar.set(template, 'networkName', network.name); + } + }); + + // CHECK SYNCING + this.syncFilter = web3.eth.isSyncing(function(error, syncing) { + if (!error) { + if (syncing === true) { + console.log('Node started syncing, stopping app operation'); + web3.reset(true); + } else if (_.isObject(syncing)) { + syncing.progress = Math.floor( + (syncing.currentBlock - syncing.startingBlock) / + (syncing.highestBlock - syncing.startingBlock) * + 100 + ); + syncing.blockDiff = numeral( + syncing.highestBlock - syncing.currentBlock + ).format('0,0'); + + TemplateVar.set(template, 'syncing', syncing); + } else { + console.log('Restart app operation again'); + + TemplateVar.set(template, 'syncing', false); + } + } + }); + + // CHECK PEER COUNT + this.peerCountIntervalId = null; + + TemplateVar.set('peerCount', 0); + getPeerCount(template); + + Meteor.clearInterval(this.peerCountIntervalId); + this.peerCountIntervalId = setInterval(function() { + getPeerCount(template); + }, 1000); + + // CHECK MINING and HASHRATE + this.miningIntervalId = null; + + TemplateVar.set('mining', false); + getMining(template); + + Meteor.clearInterval(this.miningIntervalId); + this.miningIntervalId = setInterval(function() { + getMining(template); + }, 1000); +}); + +Template['elements_nodeInfo'].onDestroyed(function() { + Meteor.clearInterval(this.peerCountIntervalId); + + if (this.syncFilter) { + this.syncFilter.stopWatching(); + } +}); + +Template['elements_nodeInfo'].helpers({ + /** + Formats the last block number + + @method (formattedBlockNumber) + @return {String} + */ + formattedBlockNumber: function() { + return numeral(EthBlocks.latest.number).format('0,0'); + }, + /** + Formats the time since the last block + + @method (timeSinceBlock) + */ + timeSinceBlock: function() { + var timeSince = moment(EthBlocks.latest.timestamp, 'X'); + var now = moment(); + var diff = now.diff(timeSince, 'seconds'); + + if (!EthBlocks.latest.timestamp) { + return '-'; + } + + if (diff > 60) { + Helpers.rerun['10s'].tick(); + return timeSince.fromNow(true); + } else if (diff < 2) { + Helpers.rerun['1s'].tick(); + return ( + ' ' + + TAPi18n.__('mist.nodeInfo.blockReceivedShort') + + '' + ); + } + + Helpers.rerun['1s'].tick(); + return diff + 's'; + } +}); diff --git a/interface/client/templates/index.html b/interface/client/templates/index.html new file mode 100644 index 0000000..82d1d53 --- /dev/null +++ b/interface/client/templates/index.html @@ -0,0 +1,19 @@ + + + + + + + + +
+ + {{> Template.dynamic template=renderApp}} + + {{> GlobalNotifications}} + +
+ + + + diff --git a/interface/client/templates/index.js b/interface/client/templates/index.js new file mode 100644 index 0000000..0485880 --- /dev/null +++ b/interface/client/templates/index.js @@ -0,0 +1,61 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The body template + +@class [template] body +@constructor +*/ + +// Generic windows reuse windows by switching the template +ipc.on('uiAction_switchTemplate', (e, templateName) => { + TemplateVar.setTo( + '#generic-body', + 'MainRenderTemplate', + `popupWindows_${templateName}` + ); +}); + +Template.body.helpers({ + /** + Chooses the view to render at start + + @method renderApp + */ + renderApp: function() { + // Generic windows return the TemplateVar if set in the ipc call above + const template = TemplateVar.get('MainRenderTemplate'); + if (template) { + return template; + } + + if (_.isEmpty(location.hash)) { + $('title').text('Mist'); + return 'layout_main'; + } else { + var renderWindow = location.hash.match(/#([a-zA-Z]*)_?/); + + if (renderWindow.length > 0) { + return 'popupWindows_' + renderWindow[1]; + } else { + return false; + } + } + } +}); + +/* +Template.body.events({ + /** + On drag over prevent redirect + + @event dragover body > *, drop body > * + * + 'dragover body > *, drop body > *': function(e){ + e.preventDefault(); + }, +});*/ diff --git a/interface/client/templates/layout/browserBar.html b/interface/client/templates/layout/browserBar.html new file mode 100644 index 0000000..6261cba --- /dev/null +++ b/interface/client/templates/layout/browserBar.html @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/interface/client/templates/layout/browserBar.js b/interface/client/templates/layout/browserBar.js new file mode 100644 index 0000000..a98912f --- /dev/null +++ b/interface/client/templates/layout/browserBar.js @@ -0,0 +1,173 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The browserBar template + +@class [template] layout_browserBar +@constructor +*/ + +Template['layout_browserBar'].onRendered(function() { + var template = this; +}); + +Template['layout_browserBar'].helpers({ + /** + Break the URL in protocol, domain and folders + + @method (breadcrumb) + */ + breadcrumb: function() { + if (!this || !this.url) { + return; + } + try { + return Helpers.generateBreadcrumb(new URL(this.url)); + } catch (e) { + return; + } + }, + + /** + Returns the current dapp + + @method (dapp) + */ + dapp: function() { + return Tabs.findOne(LocalStore.get('selectedTab')); + }, + /** + Returns dapps current accounts + + @method (dappAccounts) + */ + dappAccounts: function() { + if (this.permissions) { + return EthAccounts.find({ + address: { $in: this.permissions.accounts || [] } + }); + } + }, + /** + Show the add button, when on a dapp and in doogle + + @method (isBrowser) + */ + isBrowser: function() { + return LocalStore.get('selectedTab') === 'browser'; + }, + /** + Current selected view + + @method (currentWebView) + */ + currentWebView: function() { + return '.webview webview[data-id="' + LocalStore.get('selectedTab') + '"]'; + } +}); + +Template['layout_browserBar'].events({ + /* + Go back in the dapps browser history + + @event click button.back + */ + 'click button.back': function() { + var webview = Helpers.getWebview(LocalStore.get('selectedTab')); + + if (webview && webview.canGoBack()) { + webview.goBack(); + } + }, + /* + Reload the current webview + + @event click button.reload + */ + 'click button.reload': function() { + var webview = Helpers.getWebview(LocalStore.get('selectedTab')); + + if (webview) { + webview.reload(); + } + }, + /* + Remove the current selected tab + + // TODO show popup before to confirm + + @event click button.remove-tab + */ + 'click button.remove-tab': function() { + var tabId = LocalStore.get('selectedTab'); + + Tabs.remove(tabId); + LocalStore.set('selectedTab', 'browser'); + }, + /** + Show connect account popup + + @event click .app-bar > button.accounts' + */ + 'click .app-bar > button.accounts': function(e, template) { + LocalStore.set('chosenTab', LocalStore.get('selectedTab')); // needed by connectAccount + mist.requestAccount(function(e, addresses) { + var tabId = LocalStore.get('selectedTab'); + + dbSync.syncDataFromBackend(LastVisitedPages); + dbSync.syncDataFromBackend(Tabs).then(function() { + Tabs.update(tabId, { + $set: { + 'permissions.accounts': addresses + } + }); + }); + }); + }, + /* + Hide the app bar on input blur + + @event blur + */ + 'blur .app-bar > form.url .url-input': function(e, template) { + template.$('.app-bar').removeClass('show-bar'); + }, + /* + Stop hiding the app bar + + @event mouseenter .app-bar + */ + 'mouseenter .app-bar': function(e, template) { + clearTimeout(TemplateVar.get('timeoutId')); + }, + /* + Send the domain + + @event submit + */ + submit: function(e, template) { + var url = Helpers.formatUrl(template.$('.url-input')[0].value); + + // remove focus from url input + template.$('.url-input').blur(); + + // look in tabs + var url = Helpers.sanitizeUrl(url); + var tabId = Helpers.getTabIdByUrl(url); + + console.log('Submitted new URL: ' + url); + + // update current tab url + Tabs.update(tabId, { + $set: { + url: url, + redirect: url + } + }); + LocalStore.set('selectedTab', tabId); + } +}); diff --git a/interface/client/templates/layout/main.html b/interface/client/templates/layout/main.html new file mode 100644 index 0000000..c40e566 --- /dev/null +++ b/interface/client/templates/layout/main.html @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/interface/client/templates/layout/sidebar.html b/interface/client/templates/layout/sidebar.html new file mode 100644 index 0000000..71203a7 --- /dev/null +++ b/interface/client/templates/layout/sidebar.html @@ -0,0 +1,71 @@ + diff --git a/interface/client/templates/layout/sidebar.js b/interface/client/templates/layout/sidebar.js new file mode 100644 index 0000000..e097161 --- /dev/null +++ b/interface/client/templates/layout/sidebar.js @@ -0,0 +1,235 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The sidebar template + +@class [template] layout_sidebar +@constructor +*/ + +Template['layout_sidebar'].onRendered(function() { + var template = this, + $ul = template.$('nav > ul'); + + $ul.sortable({ + containment: 'aside.sidebar', + axis: 'y', + // tolerance: 'pointer', + items: '> li:not(.browser)', + handle: 'button.main', + cancel: '.browser', + cursor: 'move', + delay: 150, + revert: 200, + start: function(e) { + $ul.sortable('refreshPositions'); + }, + update: function(e) { + // iterate over the lis and reposition the items + $ul.find('> li').each(function(index, test) { + var id = $(this).data('tab-id'); + if (id) { + Tabs.update(id, { $set: { position: index + 1 } }); + } + }); + } + }); + + template.$('[data-tab-id]').on('mouseover', function() {}); +}); + +Template['layout_sidebar'].helpers({ + /** + Return the tabs + + @method (tabs) + */ + tabs: function() { + return Tabs.find({}, { sort: { position: 1 } }).fetch(); + }, + /** + Return the correct name + + @method (name) + */ + name: function() { + return this._id === 'browser' + ? TAPi18n.__('mist.sidebar.buttons.browser') + : this.name; + }, + /** + Return the correct dapp icon + + @method (icon) + */ + icon: function() { + return this._id === 'browser' ? 'icons/browse-icon@2x.png' : this.icon; + }, + /** + Return the tabs sub menu as array + + @method (subMenu) + */ + subMenu: function() { + var template = Template.instance(); + + if (this._id === 'browser') { + return LastVisitedPages.find({}, { sort: { timestamp: -1 }, limit: 25 }); + } else if (this.menu) { + var menu = _.toArray(this.menu); + + // sort by position + menu.sort(function(a, b) { + if (a.position < b.position) { + return -1; + } + if (a.position > b.position) { + return 1; + } + return 0; + }); + + return menu; + } + }, + /** + Returns connected accounts for dapp + + @method (dappAccounts) + */ + dappAccounts: function(limit) { + if (this.permissions) { + if (limit) { + return EthAccounts.find( + { address: { $in: this.permissions.accounts || [] } }, + { limit: limit } + ); + } + return EthAccounts.find({ + address: { $in: this.permissions.accounts || [] } + }); + } + }, + /** + Determines if the current tab is visible + + @method (isSelected) + */ + isSelected: function() { + return LocalStore.get('selectedTab') === (this._id || 'browser') + ? 'selected' + : ''; + }, + /** + It defines which tabs will have a remove button on the interface + + @method (tabShouldBeRemovable) + */ + tabShouldBeRemovable: function() { + return !_.contains(['browser', 'wallet'], this._id); + } +}); + +Template['layout_sidebar'].events({ + /** + Select the current visible tab + + @event click button.main + */ + 'click nav button.main': function(e, template) { + LocalStore.set('selectedTab', this._id || 'browser'); + }, + /** + Call the submenu dapp callback + + @event click ul.sub-menu button + */ + 'click nav ul.sub-menu button': function(e, template) { + var tabId = $(e.currentTarget) + .parent() + .parents('li') + .data('tab-id'); + var webview = $('webview[data-id="' + tabId + '"]')[0]; + + // browser + if (tabId === 'browser') { + webviewLoadStart.call(webview, tabId, { + newURL: this.url, + type: 'side-bar-click', + preventDefault: function() {} + }); + + // dapp tab + } else if (webview) { + webview.send('mistAPI_callMenuFunction', this.id); + LocalStore.set('selectedTab', tabId); + } + }, + /** + Remove the current selected tab + + // TODO show popup before to confirm + + @event click button.remove-tab + */ + 'click button.remove-tab': function() { + if (LocalStore.get('selectedTab') === this._id) { + LocalStore.set('selectedTab', 'browser'); + } + + Tabs.remove(this._id); + }, + /** + Show connect account popup + + @event click .accounts button' + */ + 'click .accounts button': function(e, template) { + var initialTabCount = Tabs.find().fetch().length; + LocalStore.set('selectedTab', this._id); + var initialTabId = this._id; + + mist.requestAccount(function(ev, addresses) { + dbSync.syncDataFromBackend(LastVisitedPages); + dbSync.syncDataFromBackend(Tabs).then(function() { + var tabCount = Tabs.find().fetch().length; + var tabId; + if (tabCount > initialTabCount) { + // browse tab was pinned + tabId = Tabs.findOne({}, { sort: { position: -1 }, limit: 1 }); + } else { + tabId = initialTabId; + } + Tabs.update(tabId, { + $set: { + 'permissions.accounts': addresses + } + }); + }); + }); + }, + + /** + Shows dapp submenu + + @event mouseenter .sidebar-menu > li + */ + 'mouseenter .sidebar-menu > li': function(e, template) { + var $this = $(e.currentTarget); + var tabTopOffset = $this.offset().top; + var $submenuContainer = $this.find('.submenu-container'); + var $submenu = $this.find('.sub-menu'); + var submenuHeaderHeight = $this.find('header').outerHeight(); + var windowHeight = $(window).outerHeight(); + + $submenuContainer.css('top', tabTopOffset + 'px'); + $submenu.css( + 'max-height', + windowHeight - tabTopOffset - submenuHeaderHeight - 30 + 'px' + ); + } +}); diff --git a/interface/client/templates/layout/webviews.html b/interface/client/templates/layout/webviews.html new file mode 100644 index 0000000..e4d47bb --- /dev/null +++ b/interface/client/templates/layout/webviews.html @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/interface/client/templates/layout/webviews.js b/interface/client/templates/layout/webviews.js new file mode 100644 index 0000000..8724f2b --- /dev/null +++ b/interface/client/templates/layout/webviews.js @@ -0,0 +1,23 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The main section template + +@class [template] layout_webviews +@constructor +*/ + +Template['layout_webviews'].helpers({ + /** + Return the tabs + + @method (tabs) + */ + tabs: function() { + return Tabs.find({}, { field: { position: 1 } }); + } +}); diff --git a/interface/client/templates/popupWindows/about.html b/interface/client/templates/popupWindows/about.html new file mode 100644 index 0000000..bfdca18 --- /dev/null +++ b/interface/client/templates/popupWindows/about.html @@ -0,0 +1,16 @@ + diff --git a/interface/client/templates/popupWindows/about.js b/interface/client/templates/popupWindows/about.js new file mode 100644 index 0000000..737009f --- /dev/null +++ b/interface/client/templates/popupWindows/about.js @@ -0,0 +1,13 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The about template + +@class [template] popupWindows_about +@constructor +*/ +Template['popupWindows_about'].onCreated(function() {}); diff --git a/interface/client/templates/popupWindows/clientUpdateAvailable.html b/interface/client/templates/popupWindows/clientUpdateAvailable.html new file mode 100644 index 0000000..d5fd203 --- /dev/null +++ b/interface/client/templates/popupWindows/clientUpdateAvailable.html @@ -0,0 +1,36 @@ + diff --git a/interface/client/templates/popupWindows/clientUpdateAvailable.js b/interface/client/templates/popupWindows/clientUpdateAvailable.js new file mode 100644 index 0000000..dd2da13 --- /dev/null +++ b/interface/client/templates/popupWindows/clientUpdateAvailable.js @@ -0,0 +1,14 @@ +/** +Template Controllers + +@module Templates +*/ + +Template['popupWindows_clientUpdateAvailable'].events({ + 'click .ok': function(e) { + ipc.send('backendAction_windowCallback', 'update'); + }, + 'click .cancel': function(e) { + ipc.send('backendAction_windowCallback', 'skip'); + } +}); diff --git a/interface/client/templates/popupWindows/connectAccount.html b/interface/client/templates/popupWindows/connectAccount.html new file mode 100644 index 0000000..ad22dae --- /dev/null +++ b/interface/client/templates/popupWindows/connectAccount.html @@ -0,0 +1,72 @@ + diff --git a/interface/client/templates/popupWindows/connectAccount.js b/interface/client/templates/popupWindows/connectAccount.js new file mode 100644 index 0000000..37fc070 --- /dev/null +++ b/interface/client/templates/popupWindows/connectAccount.js @@ -0,0 +1,182 @@ +var pinToSidebar = function() { + var selectedTab = TemplateVar.get('tab'); + + if (selectedTab) { + var existingUserTab = Helpers.getTabIdByUrl(selectedTab.url); + + if (existingUserTab === 'browser') { + var newTabId = Tabs.insert({ + url: selectedTab.url, + redirect: selectedTab.url, + name: selectedTab.name, + menu: {}, + position: Tabs.find().count() + 1 + }); + LocalStore.set('selectedTab', newTabId); + } else if (existingUserTab) { + LocalStore.set('selectedTab', existingUserTab); + } + + if (selectedTab._id === 'browser') { + var sameLastPage; + + // move the current browser tab to the last visited page + var lastPageItems = LastVisitedPages.find( + {}, + { limit: 2, sort: { timestamp: -1 } } + ).fetch(); + var lastPage = lastPageItems.pop(); + var lastPageURL = lastPage ? lastPage.url : 'http://about:blank'; + Tabs.update('browser', { + url: lastPageURL, + redirect: lastPageURL + }); + + // remove last page form last pages + if ( + (sameLastPage = LastVisitedPages.findOne({ + url: selectedTab.url + })) + ) { + LastVisitedPages.remove(sameLastPage._id); + } + } + } +}; + +var updateSelectedTabAccounts = function(accounts) { + var tabId = TemplateVar.get('selectedTab')._id; + Tabs.update(tabId, { + $set: { + 'permissions.accounts': accounts + } + }); +}; + +Template['popupWindows_connectAccount'].onCreated(function() { + this.autorun(function() { + TemplateVar.set('tab', Tabs.findOne(LocalStore.get('selectedTab'))); + + var tab = TemplateVar.get('tab'); + var accounts = + tab && tab.permissions && tab.permissions.accounts + ? tab.permissions.accounts + : []; + TemplateVar.set('accounts', accounts); + }); +}); + +Template['popupWindows_connectAccount'].helpers({ + /** + Returns the current dapp + + @method (dapp) + */ + dapp: function() { + return TemplateVar.get('tab'); + }, + /** + Returns a cleaner version of URL + + @method (dappFriendlyURL) + */ + dappFriendlyURL: function() { + var currentTab = TemplateVar.get('tab'); + if (currentTab && currentTab.url) { + return currentTab.url + .replace(/^https?:\/\/(www\.)?/, '') + .replace(/\/$/, ''); + } + }, + /** + Return the number of accounts this tab has permission for. + + @method accountNumber + @return {Number} + */ + accountNumber: function() { + var accounts = _.pluck(EthAccounts.find().fetch(), 'address'); + + return _.intersection(accounts, TemplateVar.get('accounts')).length; + }, + /** + Return an array with the selected accounts. + + @method selectedAccounts + @return {Array} + */ + selectedAccounts: function() { + var accounts = _.pluck(EthAccounts.find().fetch(), 'address'); + return _.intersection(accounts, TemplateVar.get('accounts')); + }, + /** + Return "selected" if the current account is allowed in that dapp. + + @method selected + @return {String} "selected" + */ + selected: function() { + return _.contains(TemplateVar.get('accounts'), this.address) + ? 'selected' + : ''; + } +}); + +Template['popupWindows_connectAccount'].events({ + /** + Toggles dapp account list selection. + + @event click .dapp-account-list button + */ + 'click .dapp-account-list button': function(e, template) { + e.preventDefault(); + var accounts = TemplateVar.get('accounts'); + + if (!_.contains(accounts, this.address)) { + accounts.push(this.address); + } else { + accounts = _.without(accounts, this.address); + } + + TemplateVar.set(template, 'accounts', accounts); + }, + /** + Closes the popup + + @event click .cancel + */ + 'click .cancel': function(e) { + ipc.send('backendAction_closePopupWindow'); + }, + /** + - Confirm or cancel the accounts available for this dapp and reload the dapp. + + @event click button.confirm, click button.cancel + */ + 'click .ok, click .stay-anonymous': function(e) { + e.preventDefault(); + + var accounts = TemplateVar.get('accounts'); + + // Pin to sidebar, if needed + if ($('#pin-to-sidebar')[0].checked) { + pinToSidebar(); + } + + accounts = _.unique(_.flatten(accounts)); + + // reload the webview + ipc.send('backendAction_windowMessageToOwner', null, accounts); + setTimeout(function() { + ipc.send('backendAction_closePopupWindow'); + }, 600); + }, + /** + Create account + + @event click button.create-account + */ + 'click button.create-account': function(e, template) { + ipc.send('mistAPI_createAccount'); + } +}); diff --git a/interface/client/templates/popupWindows/generic.html b/interface/client/templates/popupWindows/generic.html new file mode 100644 index 0000000..7155242 --- /dev/null +++ b/interface/client/templates/popupWindows/generic.html @@ -0,0 +1,4 @@ + diff --git a/interface/client/templates/popupWindows/generic.js b/interface/client/templates/popupWindows/generic.js new file mode 100644 index 0000000..68e0f26 --- /dev/null +++ b/interface/client/templates/popupWindows/generic.js @@ -0,0 +1,13 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The about template + +@class [template] popupWindows_generic +@constructor +*/ +Template['popupWindows_generic'].onCreated(function() {}); diff --git a/interface/client/templates/popupWindows/importAccount.html b/interface/client/templates/popupWindows/importAccount.html new file mode 100644 index 0000000..6b792f2 --- /dev/null +++ b/interface/client/templates/popupWindows/importAccount.html @@ -0,0 +1,31 @@ + diff --git a/interface/client/templates/popupWindows/importAccount.js b/interface/client/templates/popupWindows/importAccount.js new file mode 100644 index 0000000..d8d7d88 --- /dev/null +++ b/interface/client/templates/popupWindows/importAccount.js @@ -0,0 +1,163 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The importAccount import template + +@class [template] popupWindows_importAccount +@constructor +*/ + +Template['popupWindows_importAccount'].helpers({ + /** + Show password + + @method showPassword + */ + showPassword: function() { + return TemplateVar.get('showPassword') ? 'text' : 'password'; + } +}); + +Template['popupWindows_importAccount'].events({ + /** + On drag enter, change class + + @event dragenter .dropable + */ + 'dragenter .dropable': function(e) { + $(e.currentTarget).addClass('active'); + }, + /** + On drag leave, change class + + @event dragleave .dropable + */ + 'dragleave .dropable': function(e) { + $(e.currentTarget).removeClass('active'); + }, + /** + When the file is droped, read the path + + @event drop .dropable + */ + 'drop .dropable': function(e, template) { + e.preventDefault(); + + if (e.originalEvent.dataTransfer) { + files = e.originalEvent.dataTransfer.files; + } + + if (files.length) { + ipc.send('backendAction_checkWalletFile', files[0].path); + + ipc.on('uiAction_checkedWalletFile', function(ev, error, type) { + switch (type) { + case 'presale': + console.log(`Imported ${type} account`); + TemplateVar.set(template, 'filePath', files[0].path); + Tracker.afterFlush(function() { + template.$('.password').focus(); + }); + break; + case 'web3': + console.log(`Imported ${type} account`); + TemplateVar.set(template, 'filePath', files[0].path); + TemplateVar.set(template, 'importing', true); + setTimeout(function() { + ipc.send('backendAction_closePopupWindow'); + }, 750); + break; + default: + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.onboarding.errors.unknownFile' + ), + duration: 4 + }); + } + }); + } + + $(e.currentTarget).removeClass('active'); + }, + /** + On drag over prevent redirect + + @event dragover .dropable + */ + 'dragover .dropable': function(e) { + e.preventDefault(); + }, + /** + On show password + + @event click .show-password + */ + 'click .show-password': function(e) { + TemplateVar.set('showPassword', e.currentTarget.checked); + }, + /** + Checks the password match sends the file path and password to the mist backend to import + + @event submit form + */ + 'submit form': function(e, template) { + var pw = template.find('input.password').value; + + ipc.send('backendAction_importWalletFile', TemplateVar.get('filePath'), pw); + + TemplateVar.set('importing', true); + ipc.on('uiAction_importedWalletFile', function(ev, error, address) { + TemplateVar.set(template, 'importing', false); + TemplateVar.set(template, 'filePath', false); + + if (address) { + ipc.removeAllListeners('uiAction_importedWalletFile'); + console.log('Imported account: ', address); + + // move to add account screen, when in the onboarding window + if ($('.onboarding-start')[0]) { + TemplateVar.setTo( + '.onboarding-account', + 'newAccount', + web3.toChecksumAddress(address) + ); + TemplateVar.setTo('.onboarding-screen', 'currentActive', 'account'); + + // otherwise simply close the window + } else { + ipc.send('backendAction_closePopupWindow'); + } + } else { + console.log('Import failed', error); + + if (error === 'Decryption Failed') { + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.onboarding.errors.wrongPassword' + ), + duration: 4 + }); + } else { + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.onboarding.errors.importFailed', + { + error + } + ), + duration: 4 + }); + } + } + }); + + // clear form + template.find('input.password').value = ''; + pw = null; + } +}); diff --git a/interface/client/templates/popupWindows/loadingWindow.html b/interface/client/templates/popupWindows/loadingWindow.html new file mode 100644 index 0000000..04560a8 --- /dev/null +++ b/interface/client/templates/popupWindows/loadingWindow.html @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/interface/client/templates/popupWindows/requestAccount.html b/interface/client/templates/popupWindows/requestAccount.html new file mode 100644 index 0000000..c2a37ea --- /dev/null +++ b/interface/client/templates/popupWindows/requestAccount.html @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/interface/client/templates/popupWindows/requestAccount.js b/interface/client/templates/popupWindows/requestAccount.js new file mode 100644 index 0000000..aed232d --- /dev/null +++ b/interface/client/templates/popupWindows/requestAccount.js @@ -0,0 +1,84 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The request account popup window template + +@class [template] popupWindows_requestAccount +@constructor +*/ + +Template['popupWindows_requestAccount'].onRendered(function() { + this.$('input.password').focus(); + TemplateVar.set('showPassword', false); +}); + +Template['popupWindows_requestAccount'].helpers({ + passwordInputType: function() { + return TemplateVar.get('showPassword') ? 'text' : 'password'; + } +}); + +Template['popupWindows_requestAccount'].events({ + 'click .cancel': function() { + ipc.send('backendAction_closePopupWindow'); + }, + 'click .show-password': function(e) { + TemplateVar.set('showPassword', e.currentTarget.checked); + }, + 'submit form': function(e, template) { + e.preventDefault(); + var pw = template.find('input.password').value; + var pwRepeat = template.find('input.password-repeat').value; + + // ask for password repeat + if (!pwRepeat) { + TemplateVar.set('password-repeat', true); + template.$('input.password-repeat').focus(); + + // stop here so we dont set the password repeat to false + return; + } + + // check passwords + if (pw !== pwRepeat) { + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.requestAccount.errors.passwordMismatch' + ), + duration: 3 + }); + } else if (pw && pw.length < 8) { + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.requestAccount.errors.passwordTooShort' + ), + duration: 3 + }); + } else if (pw && pw.length >= 8) { + TemplateVar.set('creating', true); + web3.personal.newAccount(pwRepeat, function(e, res) { + if (!e) { + ipc.send('backendAction_windowMessageToOwner', null, res); + } else { + ipc.send('backendAction_windowMessageToOwner', e); + } + + TemplateVar.set(template, 'creating', false); + + // notifiy about backing up! + alert(TAPi18n.__('mist.popupWindows.requestAccount.backupHint')); + + ipc.send('backendAction_closePopupWindow'); + }); + } + + TemplateVar.set('password-repeat', false); + template.find('input.password-repeat').value = ''; + template.find('input.password').value = ''; + pw = pwRepeat = null; + } +}); diff --git a/interface/client/templates/popupWindows/sendTransactionConfirmation.html b/interface/client/templates/popupWindows/sendTransactionConfirmation.html new file mode 100644 index 0000000..7b60c79 --- /dev/null +++ b/interface/client/templates/popupWindows/sendTransactionConfirmation.html @@ -0,0 +1,181 @@ + diff --git a/interface/client/templates/popupWindows/sendTransactionConfirmation.js b/interface/client/templates/popupWindows/sendTransactionConfirmation.js new file mode 100644 index 0000000..e57fd89 --- /dev/null +++ b/interface/client/templates/popupWindows/sendTransactionConfirmation.js @@ -0,0 +1,495 @@ +/** +Template Controllers + +@module Templates +*/ + +var setWindowSize = function(template) { + Tracker.afterFlush(function() { + ipc.send( + 'backendAction_setWindowSize', + 580, + template.$('.popup-windows .inner-container').height() + 240 + ); + }); +}; + +var defaultEstimateGas = 50000000; + +/** +The sendTransaction confirmation popup window template + +@class [template] popupWindows_sendTransactionConfirmation +@constructor +*/ + +/** +Takes a 4-byte function signature and does a best-effort conversion to a +human readable text signature. + +@method (lookupFunctionSignature) +*/ +var lookupFunctionSignature = function(data, remoteLookup) { + return new Q(function(resolve, reject) { + if (data && data.length > 8) { + var bytesSignature = + data.substr(0, 2) === '0x' + ? data.substr(0, 10) + : '0x' + data.substr(0, 8); + + if (remoteLookup) { + https + .get( + 'https://www.4byte.directory/api/v1/signatures/?hex_signature=' + + bytesSignature, + function(response) { + var body = ''; + + response.on('data', function(chunk) { + body += chunk; + }); + + response.on('end', function() { + var responseData = JSON.parse(body); + if (responseData.results.length) { + resolve(responseData.results[0].text_signature); + } else { + resolve(bytesSignature); + } + }); + } + ) + .on('error', function(error) { + console.warn('Error querying Function Signature Registry.', err); + reject(bytesSignature); + }); + } else if (_.first(window.SIGNATURES[bytesSignature])) { + resolve(_.first(window.SIGNATURES[bytesSignature])); + } else { + reject(bytesSignature); + } + } else { + reject(undefined); + } + }); +}; + +var localSignatureLookup = function(data) { + return lookupFunctionSignature(data, false); +}; + +var remoteSignatureLookup = function(data) { + return lookupFunctionSignature(data, true); +}; + +var signatureLookupCallback = function(textSignature) { + // Clean version of function signature. Striping params + TemplateVar.set( + template, + 'executionFunction', + textSignature.replace(/\(.+$/g, '') + ); + TemplateVar.set(template, 'hasSignature', true); + + var params = textSignature.match(/\((.+)\)/i); + if (params) { + console.log('params sent', params); + TemplateVar.set(template, 'executionFunctionParamTypes', params); + ipc.send('backendAction_decodeFunctionSignature', textSignature, data.data); + } +}; + +Template['popupWindows_sendTransactionConfirmation'].onCreated(function() { + var template = this; + + ipc.on('uiAction_decodedFunctionSignatures', function(event, params) { + console.log('params returned', params); + TemplateVar.set(template, 'params', params); + }); + + // check reactively if provided gas is enough + this.autorun(function() { + if ( + TemplateVar.get('estimatedGas') > Number(TemplateVar.get('providedGas')) + ) { + TemplateVar.set('gasError', 'notEnoughGas'); + } else if (TemplateVar.get('estimatedGas') > 4000000) { + TemplateVar.set('gasError', 'overBlockGasLimit'); + } else { + TemplateVar.set('gasError', null); + } + }); + + // check inital data and gas estimates + this.autorun(function() { + TemplateVar.set(template, 'displayDecodedParams', true); + + var data = Session.get('data'); + + if (data) { + // set window size + setWindowSize(template); + + // set provided gas to templateVar + TemplateVar.set('providedGas', data.gas || 0); + TemplateVar.set('initialProvidedGas', data.gas || 0); + + // add gasPrice if not set + if (!data.gasPrice) { + web3.eth.getGasPrice(function(e, res) { + if (!e) { + data.gasPrice = '0x' + res.toString(16); + Session.set('data', data); + } + }); + } + + // check if to is a contract + if (data.to) { + web3.eth.getCode(data.to, function(e, res) { + if (!e && res && res.length > 2) { + TemplateVar.set(template, 'toIsContract', true); + setWindowSize(template); + } + }); + + if (data.data) { + localSignatureLookup(data.data) + .then(function(textSignature) { + // Clean version of function signature. Striping params + TemplateVar.set( + template, + 'executionFunction', + textSignature.replace(/\(.+$/g, '') + ); + TemplateVar.set(template, 'hasSignature', true); + + var params = textSignature.match(/\((.+)\)/i); + if (params) { + TemplateVar.set( + template, + 'executionFunctionParamTypes', + params + ); + ipc.send( + 'backendAction_decodeFunctionSignature', + textSignature, + data.data + ); + } + }) + .catch(function(bytesSignature) { + TemplateVar.set(template, 'executionFunction', bytesSignature); + TemplateVar.set(template, 'hasSignature', false); + }); + } + } + if (data.from) { + web3.eth.getCode(data.from, function(e, res) { + if (!e && res && res.length > 2) { + TemplateVar.set(template, 'fromIsContract', true); + } + }); + } + + // estimate gas usage + var estimateData = _.clone(data); + estimateData.gas = defaultEstimateGas; + web3.eth.estimateGas(estimateData, function(e, res) { + console.log('Estimated gas: ', res, e); + if (!e && res) { + // set the gas to the estimation, if not provided or lower + Tracker.nonreactive(function() { + var gas = Number(TemplateVar.get(template, 'providedGas')); + + if (res === defaultEstimateGas) { + return TemplateVar.set(template, 'estimatedGas', 'invalid'); + } + + TemplateVar.set(template, 'estimatedGas', res); + + if (!gas && res) { + TemplateVar.set(template, 'providedGas', res + 100000); + TemplateVar.set(template, 'initialProvidedGas', res + 100000); + } + }); + } + }); + } + }); +}); + +Template['popupWindows_sendTransactionConfirmation'].onRendered(function() { + var template = this; + + Meteor.setTimeout(function() { + template.$('input[type="password"]').focus(); + }, 200); +}); + +Template['popupWindows_sendTransactionConfirmation'].helpers({ + /** + Returns the total amount + + @method (totalAmount) + */ + totalAmount: function() { + var amount = EthTools.formatBalance( + this.value, + '0,0.00[0000000000000000]', + 'ether' + ); + var dotPos = ~amount.indexOf('.') + ? amount.indexOf('.') + 3 + : amount.indexOf(',') + 3; + + return amount + ? amount.substr(0, dotPos) + + '' + + amount.substr(dotPos) + + '' + : '0'; + }, + /** + Calculates the fee used for this transaction in ether + + @method (estimatedFee) + */ + estimatedFee: function() { + var gas = TemplateVar.get('estimatedGas'); + if (gas && this.gasPrice) { + return EthTools.formatBalance( + new BigNumber(gas, 10).times(new BigNumber(this.gasPrice, 10)), + '0,0.0[0000000] unit', + 'ether' + ); + } + }, + /** + Calculates the provided gas amount in ether + + @method (providedGas) + */ + providedGas: function() { + var gas = TemplateVar.get('providedGas'); + if (gas && this.gasPrice) { + return EthTools.formatBalance( + new BigNumber(gas, 10).times(new BigNumber(this.gasPrice, 10)), + '0,0.0[0000000]', + 'ether' + ); + } + }, + /** + Shortens the address to 0xffff...ffff + + @method (shortenAddress) + */ + shortenAddress: function(address) { + if (_.isString(address)) { + return address.substr(0, 6) + '...' + address.substr(-4); + } + }, + /** + Formats the data so that all zeros are wrapped in span.zero + + @method (formattedData) + */ + formattedData: function() { + return TemplateVar.get('toIsContract') + ? this.data + .replace(/([0]{2,})/g, '$1') + .replace(/(0x[a-f0-9]{8})/i, '$1') + : this.data.replace(/([0]{2,})/g, '$1'); + }, + + params: function() { + return TemplateVar.get('params'); + }, + /** + Formats parameters + + @method (showFormattedParams) + */ + showFormattedParams: function() { + return TemplateVar.get('params') && TemplateVar.get('displayDecodedParams'); + }, + /** + Checks if transaction will be invalid + + @method (transactionInvalid) + */ + transactionInvalid: function() { + return ( + TemplateVar.get('estimatedGas') === 'invalid' || + TemplateVar.get('estimatedGas') === 0 || + typeof TemplateVar.get('estimatedGas') === 'undefined' + ); + } +}); + +Template['popupWindows_sendTransactionConfirmation'].events({ + /** + Gets the new provided gas in ether amount and calculates the resulting providedGas + + @event change .provided-gas, input .provided-gas + */ + 'change .provided-gas, input .provided-gas': function(e, template) { + var gas = template + .$('.provided-gas') + .text() + .replace(/[, ]+/g, ''); // template.$('.provided-gas').text(); + + TemplateVar.set('providedGas', gas); + }, + /** + Increase the estimated gas + + @event click .not-enough-gas + */ + 'click .not-enough-gas': function() { + var gas = Number(TemplateVar.get('estimatedGas')) + 100000; + TemplateVar.set('initialProvidedGas', gas); + TemplateVar.set('providedGas', gas); + }, + /** + Cancel the transaction confirmation and close the popup + + @event click .cancel + */ + 'click .cancel': function() { + ipc.send( + 'backendAction_unlockedAccountAndSentTransaction', + 'Transaction not confirmed' + ); + ipc.send('backendAction_closePopupWindow'); + }, + /** + Confirm the transaction + + @event submit form + */ + 'submit form': function(e, template) { + e.preventDefault(); + + var data = Session.get('data'), + pw = template.find('input[type="password"]').value, + gas = web3.fromDecimal(TemplateVar.get('providedGas')); + + // check if account is about to send to itself + if (data.to && data.from === data.to.toLowerCase()) { + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.sendTransactionConfirmation.errors.sameAccount' + ), + duration: 5 + }); + + return false; + } + + console.log('Choosen Gas: ', gas, TemplateVar.get('providedGas')); + + if (!gas || !_.isFinite(gas)) { + return; + } else { + data.gas = gas; + } + + TemplateVar.set('unlocking', true); + + // unlock and send transaction! + web3.personal.sendTransaction(data, pw || '', function(e, res) { + pw = null; + TemplateVar.set(template, 'unlocking', false); + + if (!e && res) { + ipc.send('backendAction_unlockedAccountAndSentTransaction', null, res); + } else { + Tracker.afterFlush(function() { + template.find('input[type="password"]').value = ''; + template.$('input[type="password"]').focus(); + }); + if (e.message.indexOf('Unable to connect to socket: timeout') !== -1) { + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.sendTransactionConfirmation.errors.connectionTimeout' + ), + duration: 5 + }); + } else if ( + e.message.indexOf('could not decrypt key with given passphrase') !== + -1 + ) { + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.sendTransactionConfirmation.errors.wrongPassword' + ), + duration: 3 + }); + } else if (e.message.indexOf('multiple keys match address') !== -1) { + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.sendTransactionConfirmation.errors.multipleKeysMatchAddress' + ), + duration: 10 + }); + } else if ( + e.message.indexOf('Insufficient funds for gas * price + value') !== -1 + ) { + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.sendTransactionConfirmation.errors.insufficientFundsForGas' + ), + duration: 5 + }); + } else { + GlobalNotification.warning({ + content: e.message, + duration: 5 + }); + } + } + }); + }, + + 'click .data .toggle-panel': function() { + TemplateVar.set('displayDecodedParams', true); + }, + 'click .parameters .toggle-panel': function() { + TemplateVar.set('displayDecodedParams', false); + }, + 'click .lookup-function-signature': function(e, template) { + var data = Session.get('data'); + TemplateVar.set('lookingUpFunctionSignature', true); + + remoteSignatureLookup(data.data) + .then(function(textSignature) { + TemplateVar.set(template, 'lookingUpFunctionSignature', false); + + // Clean version of function signature. Striping params + TemplateVar.set( + template, + 'executionFunction', + textSignature.replace(/\(.+$/g, '') + ); + TemplateVar.set(template, 'hasSignature', true); + + var params = textSignature.match(/\((.+)\)/i); + if (params) { + console.log('params:', params); + TemplateVar.set(template, 'executionFunctionParamTypes', params); + ipc.send( + 'backendAction_decodeFunctionSignature', + textSignature, + data.data + ); + } + }) + .catch(function(bytesSignature) { + TemplateVar.set(template, 'lookingUpFunctionSignature', false); + TemplateVar.set(template, 'executionFunction', bytesSignature); + TemplateVar.set(template, 'hasSignature', false); + }); + } +}); diff --git a/interface/client/templates/popupWindows/splashScreen.html b/interface/client/templates/popupWindows/splashScreen.html new file mode 100644 index 0000000..3c9bd19 --- /dev/null +++ b/interface/client/templates/popupWindows/splashScreen.html @@ -0,0 +1,35 @@ + diff --git a/interface/client/templates/popupWindows/splashScreen.js b/interface/client/templates/popupWindows/splashScreen.js new file mode 100644 index 0000000..23e918e --- /dev/null +++ b/interface/client/templates/popupWindows/splashScreen.js @@ -0,0 +1,300 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The splashScreen template + +@class [template] popupWindows_splashScreen +@constructor +*/ + +/** +Contains the last state of the data + +@property lastSyncData +*/ +var lastSyncData = {}, + showNodeLog = true; + +Template['popupWindows_splashScreen'].onCreated(function() { + var template = this; + template._intervalId = null; + + ipc.on('uiAction_nodeLogText', function(e, text, data) { + if (showNodeLog && data) { + TemplateVar.set(template, 'logText', data); + TemplateVar.set(template, 'syncStatusMessage', false); + return; + } + }); + + ipc.on('uiAction_clientBinaryStatus', function(e, status) { + TemplateVar.set( + template, + 'text', + TAPi18n.__('mist.startScreen.clientBinaries.' + status) + ); + TemplateVar.set(template, 'showNetworkIndicator', status === 'done'); + TemplateVar.set(template, 'showProgressBar', false); + TemplateVar.set(template, 'showStartAppButton', false); + TemplateVar.set(template, 'showRetryConnectionButton', false); + TemplateVar.set(template, 'logText', null); + }); + + ipc.on('uiAction_nodeStatus', function(e, status, errorTag) { + switch (status) { + case 'starting': + TemplateVar.set( + template, + 'text', + TAPi18n.__('mist.startScreen.nodeStarting') + ); + showNodeLog = true; + TemplateVar.set(template, 'logText', null); + TemplateVar.set(template, 'showProgressBar', false); + TemplateVar.set(template, 'showStartAppButton', false); + TemplateVar.set(template, 'showRetryConnectionButton', false); + break; + + case 'started': + TemplateVar.set( + template, + 'text', + TAPi18n.__('mist.startScreen.nodeStarted') + ); + break; + + case 'connected': + TemplateVar.set( + template, + 'text', + TAPi18n.__('mist.startScreen.nodeConnected') + ); + lastSyncData = {}; + break; + + case 'stopping': + TemplateVar.set( + template, + 'text', + TAPi18n.__('mist.startScreen.nodeStopping') + ); + TemplateVar.set(template, 'showProgressBar', false); + TemplateVar.set(template, 'showStartAppButton', false); + break; + + case 'stopped': + TemplateVar.set( + template, + 'text', + TAPi18n.__('mist.startScreen.nodeStopped') + ); + break; + + case 'connectionTimeout': + TemplateVar.set( + template, + 'text', + TAPi18n.__('mist.startScreen.nodeConnectionTimeout') + ); + break; + + case 'error': + errorTag = 'mist.startScreen.' + (errorTag || 'nodeError'); + + TemplateVar.set(template, 'text', TAPi18n.__(errorTag)); + TemplateVar.set(template, 'showRetryConnectionButton', true); + TemplateVar.set( + template, + 'retryConnectionButtonText', + TAPi18n.__('mist.startScreen.retryConnection') + ); + break; + } + }); + + ipc.on('uiAction_nodeSyncStatus', function(e, status, data) { + console.trace('Node sync status', status, data); + + TemplateVar.set(template, 'smallClass', 'small'); + + if (status === 'inProgress') { + TemplateVar.set(template, 'showStartAppButton', true); + TemplateVar.set( + template, + 'startAppButtonText', + TAPi18n.__('mist.startScreen.launchApp') + ); + + if (data !== false) { + // if state is "in progress" and we have data + showNodeLog = false; + var translationString = ''; + + // add the data received to the object lastSyncData + lastSyncData = _.extend(lastSyncData, data || {}); + + // Select the appropriate message + if (web3.net.peerCount > 0) { + // Check which state we are + if ( + 0 < lastSyncData._displayKnownStates && + (Number(lastSyncData.pulledStates) !== + Math.round(lastSyncData._displayState) || + Number(lastSyncData.knownStates) !== + Math.round(lastSyncData._displayKnownStates)) + ) { + // Mostly downloading new states + translationString = 'mist.startScreen.nodeSyncInfoStates'; + } else { + // Mostly downloading blocks + translationString = 'mist.startScreen.nodeSyncInfo'; + } + } else { + // Not online + translationString = 'mist.startScreen.nodeSyncConnecting'; + } + + // Saves data as numbers (hex) + lastSyncData._highestBlock = lastSyncData.highestBlock; + + // saves data as pretty strings + lastSyncData.highestBlock = numeral(lastSyncData.highestBlock).format( + '0,0' + ); + + // saves to template + TemplateVar.set(template, 'lastSyncData', lastSyncData); + } else { + // It's not connected anymore + if (web3.net.peerCount > 1) { + translationString = 'mist.startScreen.nodeSyncFoundPeers'; + } else { + translationString = 'mist.startScreen.nodeSyncConnecting'; + } + + TemplateVar.set(template, 'lastSyncData', { + peers: web3.net.peerCount + }); + } + + TemplateVar.set(template, 'logText', false); + TemplateVar.set( + template, + 'text', + TAPi18n.__('mist.startScreen.nodeSyncing') + ); + TemplateVar.set(template, 'syncStatusMessage', translationString); + } + }); +}); + +Template['popupWindows_splashScreen'].helpers({ + /** + Returns the current splash screen mode + + @method mode + */ + mode: function() { + return window.mistMode; + }, + /** + Returns the icon path + + @method iconPath + */ + iconPath: function() { + return ( + 'file://' + window.dirname + '/icons/' + window.mistMode + '/icon2x.png' + ); + }, + /** + Updates the Sync Message live + + @method syncStatus + */ + syncStatus: function() { + // This functions loops trhough numbers while waiting for the node to respond + var template = Template.instance(); + Meteor.clearInterval(template._intervalId); + + // Create an interval to quickly iterate trough the numbers + template._intervalId = Meteor.setInterval(function() { + // loads data from templates + var syncData = TemplateVar.get(template, 'lastSyncData', lastSyncData); + var translationString = TemplateVar.get(template, 'syncStatusMessage'); + + if (!(syncData._displayBlock > -1)) { + // initialize the display numbers + syncData._displayBlock = Number(syncData.currentBlock); + syncData._displayState = Number(syncData.pulledStates || 0); + syncData._displayKnownStates = Number(syncData.knownStates || 0); + } else { + // Increment each them slowly to match target number + syncData._displayBlock += + (Number(syncData.currentBlock) - syncData._displayBlock) / 100; + syncData._displayState += + (Number(syncData.pulledStates || 0) - syncData._displayState) / 100; + syncData._displayKnownStates += + (Number(syncData.knownStates || 0) - syncData._displayKnownStates) / + 100; + } + + // Create the fancy strings + lastSyncData.displayBlock = numeral( + Math.round(lastSyncData._displayBlock) + ).format('0,0'); + lastSyncData.displayState = numeral( + Math.round(lastSyncData._displayState) + ).format('0,0'); + lastSyncData.displayKnownStates = numeral( + Math.round(lastSyncData._displayKnownStates) + ).format('0,0'); + + // Translate it + var translatedMessage = TAPi18n.__(translationString, syncData); + + // Calculates both progress bars + var stateProgress = null; + if (0 < lastSyncData._displayKnownStates) { + stateProgress = + lastSyncData._displayState / lastSyncData._displayKnownStates * 100; + } + + var progress = + (lastSyncData._displayBlock - Number(lastSyncData.startingBlock)) / + (Number(lastSyncData._highestBlock) - + Number(lastSyncData.startingBlock)) * + 100; + + // Saves data back to templates + TemplateVar.set(template, 'syncStatusMessageLive', translatedMessage); + TemplateVar.set(template, 'lastSyncData', syncData); + + // set progress value + if (_.isFinite(progress)) { + TemplateVar.set(template, 'showProgressBar', true); + TemplateVar.set(template, 'progress', progress); + if (null !== stateProgress) { + TemplateVar.set(template, 'showStateProgressBar', true); + TemplateVar.set(template, 'stateProgress', stateProgress); + } + } + }, 10); + + return TemplateVar.get(template, 'syncStatusMessageLive'); + } +}); + +Template['popupWindows_splashScreen'].events({ + 'click .start-app': function() { + ipc.send('backendAction_skipSync'); + }, + + 'click .retry-connection': function() { + ipc.send('retryConnection'); + } +}); diff --git a/interface/client/templates/popupWindows/unlockMasterPassword.html b/interface/client/templates/popupWindows/unlockMasterPassword.html new file mode 100644 index 0000000..0a78aab --- /dev/null +++ b/interface/client/templates/popupWindows/unlockMasterPassword.html @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/interface/client/templates/popupWindows/unlockMasterPassword.js b/interface/client/templates/popupWindows/unlockMasterPassword.js new file mode 100644 index 0000000..ba136f7 --- /dev/null +++ b/interface/client/templates/popupWindows/unlockMasterPassword.js @@ -0,0 +1,56 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The request account popup window template + +@class [template] popupWindows_unlockMasterPassword +@constructor +*/ + +Template['popupWindows_unlockMasterPassword'].onRendered(function() { + var template = this; + + template.$('input.password').focus(); + + template.autorun(function() { + var data = Session.get('data'); + + if (data && data.masterPasswordWrong) { + TemplateVar.set('unlocking', false); + + Tracker.afterFlush(function() { + template.$('input.password').focus(); + }); + + GlobalNotification.warning({ + content: TAPi18n.__( + 'mist.popupWindows.unlockMasterPassword.errors.wrongPassword' + ), + duration: 3 + }); + + Session.set('data', false); + } + }); +}); + +Template['popupWindows_unlockMasterPassword'].events({ + 'click .cancel': function() { + ipc.send('backendAction_closePopupWindow'); + }, + 'submit form': function(e, template) { + e.preventDefault(); + var pw = template.find('input.password').value; + + TemplateVar.set('unlocking', true); + + ipc.send('backendAction_unlockedMasterPassword', null, pw); + + template.find('input.password').value = ''; + pw = null; + } +}); diff --git a/interface/client/templates/popupWindows/updateAvailable.html b/interface/client/templates/popupWindows/updateAvailable.html new file mode 100644 index 0000000..7a36e52 --- /dev/null +++ b/interface/client/templates/popupWindows/updateAvailable.html @@ -0,0 +1,49 @@ + \ No newline at end of file diff --git a/interface/client/templates/popupWindows/updateAvailable.js b/interface/client/templates/popupWindows/updateAvailable.js new file mode 100644 index 0000000..464c90f --- /dev/null +++ b/interface/client/templates/popupWindows/updateAvailable.js @@ -0,0 +1,49 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The updateAvailable template + +@class [template] popupWindows_updateAvailable +@constructor +*/ +Template['popupWindows_updateAvailable'].onCreated(function() { + var template = this; + + TemplateVar.set(template, 'checking', true); + + /* + When app update check is in progress it. + */ + ipc.on('uiAction_checkUpdateInProgress', function(e, update) { + console.debug('Update check in progress...'); + + TemplateVar.set(template, 'checking', true); + }); + + /* + When app update data is received display it. + */ + ipc.on('uiAction_checkUpdateDone', function(e, update) { + console.debug('Update check done'); + + TemplateVar.set(template, 'checking', false); + + if (update) { + TemplateVar.set(template, 'update', update); + } + }); +}); + +Template['popupWindows_updateAvailable'].events({ + 'click .get-update': function(e) { + var update = TemplateVar.get('update'); + + if (update && update.url) { + ipc.send('backendAction_openExternalUrl', update.url); + } + } +}); diff --git a/interface/client/templates/views/webview.html b/interface/client/templates/views/webview.html new file mode 100644 index 0000000..98f278e --- /dev/null +++ b/interface/client/templates/views/webview.html @@ -0,0 +1,9 @@ + diff --git a/interface/client/templates/views/webview.js b/interface/client/templates/views/webview.js new file mode 100644 index 0000000..7b0c6d9 --- /dev/null +++ b/interface/client/templates/views/webview.js @@ -0,0 +1,191 @@ +/** +Template Controllers + +@module Templates +*/ + +/** +The tab template + +@class [template] views_webview +@constructor +*/ + +Template['views_webview'].onRendered(function() { + var template = this, + tabId = template.data._id, + webview = template.find('webview'); + + ipc.on('uiAction_reloadSelectedTab', function(e) { + console.log('uiAction_reloadSelectedTab', LocalStore.get('selectedTab')); + if (LocalStore.get('selectedTab') === this._id) { + var webview = Helpers.getWebview(LocalStore.get('selectedTab')); + webview.reload(); + } + }); + + webview.addEventListener('did-start-loading', function(e) { + TemplateVar.set(template, 'loading', true); + }); + webview.addEventListener('did-stop-loading', function(e) { + TemplateVar.set(template, 'loading', false); + }); + + // change url + webview.addEventListener( + 'did-navigate', + webviewChangeUrl.bind(webview, tabId) + ); + webview.addEventListener( + 'did-navigate-in-page', + webviewChangeUrl.bind(webview, tabId) + ); + webview.addEventListener( + 'did-get-redirect-request', + webviewChangeUrl.bind(webview, tabId) + ); + webview.addEventListener( + 'did-stop-loading', + webviewChangeUrl.bind(webview, tabId) + ); + + // set page history + webview.addEventListener('dom-ready', function(e) { + var titleFull = webview.getTitle(), + title = titleFull; + + if (titleFull && titleFull.length > 40) { + title = titleFull.substr(0, 40); + title += '…'; + } + + // update the title + Tabs.update(tabId, { + $set: { + name: title, + nameFull: titleFull + // url: webview.getURL(), + } + }); + + webviewLoadStop.call(this, tabId, e); + }); + + // show error pages + webview.addEventListener('did-fail-load', showError.bind(webview, tabId)); + webview.addEventListener('crashed', showError.bind(webview, tabId)); + + // Forward SWARM status code errors to showError + webview.addEventListener('did-get-response-details', function(e) { + if (e && e.resourceType === 'mainFrame' && /^bzz:\//i.test(e.newURL)) { + switch (e.httpResponseCode) { + case 500: + showError.call(webview, tabId, { + isMainFrame: true, + errorCode: 404 + }); + break; + } + } + }); + + // navigate page, and redirect to browser tab if necessary + webview.addEventListener( + 'will-navigate', + webviewLoadStart.bind(webview, tabId) + ); + webview.addEventListener( + 'did-get-redirect-request', + webviewLoadStart.bind(webview, tabId) + ); + webview.addEventListener('new-window', webviewLoadStart.bind(webview, tabId)); + + // MIST API for installed tabs/dapps + webview.addEventListener( + 'ipc-message', + mistAPIBackend.bind({ + template: template, + webview: webview + }) + ); +}); + +Template['views_webview'].helpers({ + /** + Gets the correct preloader file + + @method (preloaderFile) + */ + preloaderFile: function() { + switch (this._id) { + case 'browser': + return 'file://' + Helpers.preloaderDirname + '/browser.js'; + case 'tests': + return 'file://' + Helpers.preloaderDirname + '/tests.js'; + default: + return 'file://' + Helpers.preloaderDirname + '/dapps.js'; + } + }, + /** + Determines if the current tab is visible + + @method (isVisible) + */ + isVisible: function() { + return LocalStore.get('selectedTab') === this._id ? '' : 'hidden'; + }, + /** + Gets the current url + + @method (checkedUrl) + */ + checkedUrl: function() { + var template = Template.instance(); + var tab = Tabs.findOne(this._id, { fields: { redirect: 1 } }); + var url; + + if (tab) { + // set url only once + if (tab.redirect) { + url = tab.redirect; + + // remove redirect + Tabs.update(this._id, { + $unset: { + redirect: '' + } + }); + } + + // allow error pages + if (url && url.indexOf('file://' + dirname + '/errorPages/') === 0) { + return url; + } + + // CHECK URL and throw error if not allowed + if (!Helpers.sanitizeUrl(url, true)) { + // Prevent websites usingt the history back attacks + if (template.view.isRendered) { + // get the current webview + var webview = template.find('webview'); + webview.clearHistory(); + } + + console.warn('Not allowed URL: ' + template.url); + return 'file://' + dirname + '/errorPages/400.html'; + } + + // add url + if (url) { + template.url = url; + Tabs.update(this._id, { + $set: { + url: url + } + }); + } + + return Helpers.formatUrl(url); + } + } +}); diff --git a/interface/client/templates/webviewEvents.js b/interface/client/templates/webviewEvents.js new file mode 100644 index 0000000..e668f45 --- /dev/null +++ b/interface/client/templates/webviewEvents.js @@ -0,0 +1,151 @@ +showError = function(tabId, e) { + if (e.isMainFrame || e.killed) { + var url, + path = 'file://' + dirname + '/errorPages/'; + + if (e.killed) { + e.errorCode = 500; + } + + switch (e.errorCode) { + case -105: + url = path + '404.html'; + break; + case 404: + url = path + '404.html'; + break; + case 500: + url = path + '500.html'; + break; + } + + if (url) { + Tabs.update(tabId, { + $set: { + redirect: url + } + }); + } + } +}; + +webviewChangeUrl = function(tabId, e) { + if (e.type === 'did-navigate-in-page' && !e.isMainFrame) { + return; + } + + var url = Helpers.sanitizeUrl(e.url || this.getURL()); + + console.log(e.type, tabId, url); + + if (e.type === 'did-navigate') { + // destroy socket when navigating away + ipc.send('ipcProvider-destroy', this.getWebContents().id); + } + + // make sure to not store error pages in history + if ( + !url || + url.indexOf('mist/errorPages/') !== -1 || + url.indexOf('app.asar/errorPages/') !== -1 + ) { + return; + } + + // update the URL + Tabs.update(tabId, { + $set: { + url: url + } + }); +}; + +// fired by "did-stop-loading" +webviewLoadStop = function(tabId, e) { + var webview = this, + url = Helpers.sanitizeUrl(webview.getURL()), + title = webview.getTitle(); + + console.log(e.type, tabId, url); + + // IS BROWSER + if (tabId === 'browser') { + // ADD to doogle last visited pages + if ( + (find = _.find(LastVisitedPages.find().fetch(), function(historyEntry) { + if (!historyEntry.url) { + return; + } + var historyEntryOrigin = new URL(historyEntry.url).origin; + return url.indexOf(historyEntryOrigin) !== -1; + })) + ) { + LastVisitedPages.update(find._id, { + $set: { + timestamp: moment().unix(), + url: url + } + }); + } else { + LastVisitedPages.insert({ + name: title, + url: url, + // icon: '', + timestamp: moment().unix() + }); + } + + // ADD to doogle history + if ((find = History.findOne({ url: url }))) { + History.update(find._id, { $set: { timestamp: moment().unix() } }); + } else { + History.insert({ + name: title, + url: url, + // icon: '', + timestamp: moment().unix() + }); + } + } +}; + +// fired by "did-get-redirect-request" +// fired by "new-window" +// fired by "will-navigate" +webviewLoadStart = function(currentTabId, e) { + var webview = this; + + if (e.type === 'did-get-redirect-request' && !e.isMainFrame) { + return; + } + + console.log(e.type, currentTabId, e); + + // stop this action, as the redirect happens reactive through setting the URL attribute + e.preventDefault(); // doesnt work + webview.stop(); // doesnt work + ipc.sendSync( + 'backendAction_stopWebviewNavigation', + webview.getWebContents().id + ); + + var url = Helpers.sanitizeUrl(e.newURL || e.url); + var tabId = Helpers.getTabIdByUrl(url); + + // if new window (_blank) open in tab, or browser + if (e.type === 'new-window' && tabId === currentTabId) { + tabId = 'browser'; + } + + var tab = Tabs.findOne(tabId); + + if (tab.url !== url) { + Tabs.update(tabId, { + $set: { + redirect: url, + url: url + } + }); + } + LocalStore.set('selectedTab', tabId); +}; diff --git a/interface/client/windowEvents.js b/interface/client/windowEvents.js new file mode 100644 index 0000000..8e344e5 --- /dev/null +++ b/interface/client/windowEvents.js @@ -0,0 +1,55 @@ +// add the platform to the HTML tag +setTimeout(function() { + document.getElementsByTagName('html')[0].className = window.mist.platform; + + if (window.basePathHref) { + var base = document.createElement('base'); + + base.href = window.basePathHref; + + document.getElementsByTagName('head')[0].appendChild(base); + } +}, 200); + +$(window).on('blur', function(e) { + $('body').addClass('app-blur'); +}); +$(window).on('focus', function(e) { + $('body').removeClass('app-blur'); +}); + +// make sure files can only be dropped in the browser webview +$(window).on('dragenter', function(e) { + LocalStore.set('selectedTab', 'browser'); + ipc.send('backendAction_focusMainWindow'); +}); + +$(window).on('keydown', function(e) { + // Select tab with index when number is 1-8 + if (e.metaKey && e.keyCode >= 49 && e.keyCode <= 56) { + var index = parseInt(String.fromCharCode(e.keyCode), 10) - 1; + Helpers.selectTabWithIndex(index); + return; + } + + // RELOAD current webview + if (e.metaKey && e.keyCode === 82) { + var webview = Helpers.getWebview(LocalStore.get('selectedTab')); + if (webview) { + webview.reloadIgnoringCache(); + } + return; + } + + // Select last tab on Ctrl + 9 + if (e.metaKey && e.keyCode === 57) { + Helpers.selectLastTab(); + return; + } + + // Ctrl + tab || Ctrl + shift + tab + if (e.ctrlKey && e.keyCode === 9) { + var tabOffset = e.shiftKey ? -1 : 1; + Helpers.selectTabWithOffset(tabOffset); + } +}); diff --git a/interface/i18n/app.ca.i18n.json b/interface/i18n/app.ca.i18n.json new file mode 100644 index 0000000..88a1e22 --- /dev/null +++ b/interface/i18n/app.ca.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Carregant...", + "offline": "No s'ha pogut connectar, estàs desconectat?", + "logginIn": "iniciant sessió..." + }, + "error": { + "insufficientRights": "No tens prous drets per aquesta acció." + }, + "buttons": { + "ok": "OK", + "cancel": "Cancel·lar", + "save": "Desa", + "edit": "Edita", + "send": "Envia", + "next": "Següent", + "previous": "Anterior", + "back": "Enrere", + "skip": "Omet", + "sending": "Enviant...", + "create": "Crea", + "tryToReconnect": "Intenta reconnectar", + "stayAnonymous": "Mantenir l'anonimat", + "authorize": "Authoritza" + }, + "commonWords": { + "you": "Tu", + "send": "Envia", + "or": "o", + "of": "de", + "with": "amb", + "and": "i", + "on": "a", + "per": "per" + } +} diff --git a/interface/i18n/app.de.i18n.json b/interface/i18n/app.de.i18n.json new file mode 100644 index 0000000..6978e99 --- /dev/null +++ b/interface/i18n/app.de.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Lade...", + "offline": "Kann mich nicht verbinden, bist du offline?", + "logginIn": "Einloggen..." + }, + "error": { + "insufficientRights": "Du hast nicht genügend Rechte für diese Aktion." + }, + "buttons": { + "ok": "OK", + "cancel": "Abbrechen", + "save": "Speichern", + "edit": "Editieren", + "send": "Senden", + "next": "Weiter", + "previous": "Zurück", + "back": "Zurück", + "skip": "Überspringen", + "sending": "Sende...", + "create": "Erstellen", + "tryToReconnect": "Versuche mich zu verbinden", + "stayAnonymous": "Anonym bleiben", + "authorize": "Autorisieren" + }, + "commonWords": { + "you": "Du", + "send": "Senden", + "or": "oder", + "of": "von", + "with": "mit", + "and": "und", + "on": "auf", + "per": "pro" + } +} diff --git a/interface/i18n/app.en.i18n.json b/interface/i18n/app.en.i18n.json new file mode 100644 index 0000000..49ec63b --- /dev/null +++ b/interface/i18n/app.en.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Loading...", + "offline": "Can't connect, are you offline?", + "logginIn": "Logging in..." + }, + "error": { + "insufficientRights": "You don't have enough rights for this action." + }, + "buttons": { + "ok": "OK", + "cancel": "Cancel", + "save": "Save", + "edit": "Edit", + "send": "Send", + "next": "Next", + "previous": "Previous", + "back": "Back", + "skip": "Skip", + "sending": "Sending...", + "create": "Create", + "tryToReconnect": "Try to reconnect", + "stayAnonymous": "Stay anonymous", + "authorize": "Authorize" + }, + "commonWords": { + "you": "You", + "send": "Send", + "or": "or", + "of": "of", + "with": "with", + "and": "and", + "on": "on", + "per": "per" + } +} diff --git a/interface/i18n/app.es.i18n.json b/interface/i18n/app.es.i18n.json new file mode 100644 index 0000000..7dffe21 --- /dev/null +++ b/interface/i18n/app.es.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Cargando...", + "offline": "No se puede conectar, estás fuera de línea?", + "logginIn": "Iniciando sesión..." + }, + "error": { + "insufficientRights": "Usted no tiene suficientes derechos para esta acción." + }, + "buttons": { + "ok": "OK", + "cancel": "Cancelar", + "save": "Guardar", + "edit": "Editar", + "send": "Enviar", + "next": "Siguiente", + "previous": "Anterior", + "back": "Atrás", + "skip": "Omitir", + "sending": "Enviando...", + "create": "Crear", + "tryToReconnect": "Intente volver a conectar", + "stayAnonymous": "Stay anonymous", + "authorize": "Authorize" + }, + "commonWords": { + "you": "Tú", + "send": "Enviar", + "or": "o", + "of": "de", + "with": "con", + "and": "y", + "on": "en", + "per": "por" + } +} \ No newline at end of file diff --git a/interface/i18n/app.fa.i18n.json b/interface/i18n/app.fa.i18n.json new file mode 100644 index 0000000..94363bb --- /dev/null +++ b/interface/i18n/app.fa.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "بارگذاری...", + "offline": "نمی توانم وصل شوم، آیا شما قطع هستید؟", + "logginIn": "بارگذاری در..." + }, + "error": { + "insufficientRights": "شما برای این عملیات دسترسی کافی ندارید." + }, + "buttons": { + "ok": "تایید", + "cancel": "لغو", + "save": "ذخیره", + "edit": "ویرایش", + "send": "ارسال", + "next": "بعدی", + "previous": "قبلی", + "back": "عقب", + "skip": "جستن", + "sending": "ارسال...", + "create": "ساختن", + "tryToReconnect": "تلاش برای وصل مجدد", + "stayAnonymous": "Stay anonymous", + "authorize": "Authorize" + }, + "commonWords": { + "you": "شما", + "send": "ارسال", + "or": "یا", + "of": "از", + "with": "با", + "and": "و", + "on": "بر", + "per": "در هر" + } +} \ No newline at end of file diff --git a/interface/i18n/app.fr.i18n.json b/interface/i18n/app.fr.i18n.json new file mode 100644 index 0000000..8daa8bc --- /dev/null +++ b/interface/i18n/app.fr.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Chargement en cours...", + "offline": "Impossible de se connecter, êtes-vous déconnecté ?", + "logginIn": "Connexion en cours..." + }, + "error": { + "insufficientRights": "Vous n'avez pas les droits pour effectuer cette action." + }, + "buttons": { + "ok": "OK", + "cancel": "Annuler", + "save": "Enregistrer", + "edit": "Modifier", + "send": "Envoyer", + "next": "Suivant", + "previous": "Précédent", + "back": "Retour", + "skip": "Ignorer", + "sending": "Envoi en cours...", + "create": "Créer", + "tryToReconnect": "Tentative de reconnexion", + "stayAnonymous": "Stay anonymous", + "authorize": "Authorize" + }, + "commonWords": { + "you": "Vous", + "send": "Envoyer", + "or": "ou", + "of": "de", + "with": "avec", + "and": "et", + "on": "sur", + "per": "par" + } +} \ No newline at end of file diff --git a/interface/i18n/app.it.i18n.json b/interface/i18n/app.it.i18n.json new file mode 100644 index 0000000..62024ed --- /dev/null +++ b/interface/i18n/app.it.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Caricamento...", + "offline": "Impossibile connettersi, sicuro di essere online?", + "logginIn": "Autenticazione..." + }, + "error": { + "insufficientRights": "Non hai sufficienti diritti per compiere quasta azione." + }, + "buttons": { + "ok": "OK", + "cancel": "Annulla", + "save": "Salva", + "edit": "Modifica", + "send": "Invia", + "next": "Prossimo", + "previous": "Precedente", + "back": "Indietro", + "skip": "Salta", + "sending": "Inviando...", + "create": "Crea", + "tryToReconnect": "Prova a riconnetterti", + "stayAnonymous": "Rimani anonimo", + "authorize": "Autorizza" + }, + "commonWords": { + "you": "Tu", + "send": "Invia", + "or": "oppure", + "of": "di", + "with": "con", + "and": "e", + "on": "su", + "per": "per" + } +} diff --git a/interface/i18n/app.ja.i18n.json b/interface/i18n/app.ja.i18n.json new file mode 100644 index 0000000..cbe3222 --- /dev/null +++ b/interface/i18n/app.ja.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "ロード中...", + "offline": "ネットワークが繋がりません。オフラインですか?", + "logginIn": "ログインしています..." + }, + "error": { + "insufficientRights": "このアクションを行うだけの権限が足りません。" + }, + "buttons": { + "ok": "OK", + "cancel": "キャンセル", + "save": "保存", + "edit": "編集", + "send": "送る", + "next": "次へ", + "previous": "前へ", + "back": "バック", + "skip": "スキップ", + "sending": "送信中...", + "create": "作成中", + "tryToReconnect": "再接続しています。", + "stayAnonymous": "匿名を保つ", + "authorize": "認証" + }, + "commonWords": { + "you": "あなた", + "send": "送る", + "or": "または", + "of": "の", + "with": "と", + "and": "と", + "on": "の上に", + "per": "ごとに" + } +} diff --git a/interface/i18n/app.ko.i18n.json b/interface/i18n/app.ko.i18n.json new file mode 100644 index 0000000..d8e3d67 --- /dev/null +++ b/interface/i18n/app.ko.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "불러오는 중...", + "offline": "연결실패, 인터넷 연결을 확인하세요.", + "logginIn": "로그인 중..." + }, + "error": { + "insufficientRights": "요청하신 명령을 실행할 권한이 없습니다." + }, + "buttons": { + "ok": "확인", + "cancel": "취소", + "save": "저장", + "edit": "수정", + "send": "보내기", + "next": "다음", + "previous": "이전", + "back": "뒤로", + "skip": "건너뛰기", + "sending": "보내는 중...", + "create": "생성", + "tryToReconnect": "재연결 시도", + "stayAnonymous": "Stay anonymous", + "authorize": "권한 인증" + }, + "commonWords": { + "you": "당신", + "send": "보내기", + "or": "또는", + "of": "의", + "with": "와", + "and": "그리고", + "on": "위에", + "per": "당" + } +} diff --git a/interface/i18n/app.nb.i18n.json b/interface/i18n/app.nb.i18n.json new file mode 100644 index 0000000..ca32002 --- /dev/null +++ b/interface/i18n/app.nb.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Laster...", + "offline": "Kan ikke koble til. Har du ikke nett?", + "logginIn": "Logger inn..." + }, + "error": { + "insufficientRights": "Du har ikke nok rettigheter for denne handlingen." + }, + "buttons": { + "ok": "OK", + "cancel": "Avbryt", + "save": "Lagre", + "edit": "endre", + "send": "Send", + "next": "Neste", + "previous": "Forrige", + "back": "Tilbake", + "skip": "Hopp over", + "sending": "Sender...", + "create": "Lag", + "tryToReconnect": "Prøv å koble", + "stayAnonymous": "Stay anonymous", + "authorize": "Authorize" + }, + "commonWords": { + "you": "Du", + "send": "Send", + "or": "eller", + "of": "av", + "with": "med", + "and": "og", + "on": "på", + "per": "per" + } +} \ No newline at end of file diff --git a/interface/i18n/app.nl.i18n.json b/interface/i18n/app.nl.i18n.json new file mode 100644 index 0000000..a0eceea --- /dev/null +++ b/interface/i18n/app.nl.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Laden...", + "offline": "Verbinden niet mogelijk, bent u offline?", + "logginIn": "Inloggen..." + }, + "error": { + "insufficientRights": "U heeft onvoldoende rechten voor deze actie." + }, + "buttons": { + "ok": "OK", + "cancel": "Annuleren", + "save": "Opslaan", + "edit": "bijwerken", + "send": "Versturen", + "next": "Volgende", + "previous": "Vorige", + "back": "Terug", + "skip": "Overslaan", + "sending": "Verzenden...", + "create": "Aanmaken", + "tryToReconnect": "Probeer te verbinden", + "stayAnonymous": "Blijf anoniem", + "authorize": "Autoriseren" + }, + "commonWords": { + "you": "u", + "send": "Verstuur", + "or": "of", + "of": "van", + "with": "met", + "and": "en", + "on": "op", + "per": "per" + } +} \ No newline at end of file diff --git a/interface/i18n/app.pt.i18n.json b/interface/i18n/app.pt.i18n.json new file mode 100644 index 0000000..5cbad96 --- /dev/null +++ b/interface/i18n/app.pt.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Carregando...", + "offline": "Você não está conectado a internet", + "logginIn": "Autenticando..." + }, + "error": { + "insufficientRights": "Você não tem privilégios admnistrativos o suficiente" + }, + "buttons": { + "ok": "OK", + "cancel": "Cancelar", + "save": "Salvar", + "edit": "editar", + "send": "Enviar", + "next": "Próximo", + "previous": "Anterior", + "back": "Back", + "skip": "Pular", + "sending": "Enviando...", + "create": "Criar", + "tryToReconnect": "Tentando reconectar", + "stayAnonymous": "Stay anonymous", + "authorize": "Authorize" + }, + "commonWords": { + "you": "Você", + "send": "Enviar", + "or": "ou", + "of": "de", + "with": "com", + "and": "e", + "on": "em", + "per": "por" + } +} \ No newline at end of file diff --git a/interface/i18n/app.ru.i18n.json b/interface/i18n/app.ru.i18n.json new file mode 100644 index 0000000..cc7e159 --- /dev/null +++ b/interface/i18n/app.ru.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Загузка...", + "offline": "Не удается подключиться, вы в автономном режиме?", + "logginIn": "Вход в систему..." + }, + "error": { + "insufficientRights": "Вы не имеете достаточно прав для этого действия." + }, + "buttons": { + "ok": "OK", + "cancel": "Отмена", + "save": "Сохранить", + "edit": "Изменить", + "send": "Отправить", + "next": "Далее", + "previous": "Предыдущий", + "back": "Назад", + "skip": "Сбросить", + "sending": "Отправка...", + "create": "Создать", + "tryToReconnect": "Переподключить", + "stayAnonymous": "Stay anonymous", + "authorize": "Authorize" + }, + "commonWords": { + "you": "Вы", + "send": "Отправили", + "or": "или", + "of": "из", + "with": "от", + "and": "и", + "on": "на", + "per": "в" + } +} \ No newline at end of file diff --git a/interface/i18n/app.sq.i18n.json b/interface/i18n/app.sq.i18n.json new file mode 100644 index 0000000..1d2bfed --- /dev/null +++ b/interface/i18n/app.sq.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "Duke u ngarkuar...", + "offline": "Nuk mund të lidhet. Jeni të sigurt që jeni të lidhur me internetin?", + "logginIn": "Duke u lidhur..." + }, + "error": { + "insufficientRights": "Ju nuk keni të drejta të mjaftueshme për të kryer këtë veprim." + }, + "buttons": { + "ok": "OK", + "cancel": "Shuaj", + "save": "Ruaj", + "edit": "Përpuno", + "send": "Dërgo", + "next": "Më tej", + "previous": "Më parë", + "back": "Prapa", + "skip": "Kapërce", + "sending": "Duke dërguar...", + "create": "Krijo", + "tryToReconnect": "Provo të rilidhesh", + "stayAnonymous": "Qëndro anonim", + "authorize": "Autorizo" + }, + "commonWords": { + "you": "Ju", + "send": "Dërgo", + "or": "ose", + "of": "nga", + "with": "me", + "and": "dhe", + "on": "mbi", + "per": "për" + } +} diff --git a/interface/i18n/app.zh-TW.i18n.json b/interface/i18n/app.zh-TW.i18n.json new file mode 100644 index 0000000..5c5f5e1 --- /dev/null +++ b/interface/i18n/app.zh-TW.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "載入中……", + "offline": "無法連接,您的網路是否已經斷線?", + "logginIn": "登入中……" + }, + "error": { + "insufficientRights": "您沒有足夠的權限執行本次操作。" + }, + "buttons": { + "ok": "好", + "cancel": "取消", + "save": "儲存", + "edit": "編輯", + "send": "發送", + "next": "下一個", + "previous": "上一個", + "back": "返回", + "skip": "跳過", + "sending": "發送中……", + "create": "創建", + "tryToReconnect": "嘗試連線", + "stayAnonymous": "Stay anonymous", + "authorize": "Authorize" + }, + "commonWords": { + "you": "您", + "send": "發送", + "or": "或者", + "of": "的", + "with": "以及", + "and": "和", + "on": "在", + "per": "每" + } +} \ No newline at end of file diff --git a/interface/i18n/app.zh.i18n.json b/interface/i18n/app.zh.i18n.json new file mode 100644 index 0000000..9de4199 --- /dev/null +++ b/interface/i18n/app.zh.i18n.json @@ -0,0 +1,36 @@ +{ + "app": { + "loading": "载入中……", + "offline": "无法连接,你的网络是否已经掉线?", + "logginIn": "登录中……" + }, + "error": { + "insufficientRights": "你没有足够的权限执行本次操作。" + }, + "buttons": { + "ok": "好", + "cancel": "取消", + "save": "保存", + "edit": "编辑", + "send": "发送", + "next": "下一个", + "previous": "上一个", + "back": "返回", + "skip": "跳过", + "sending": "发送中……", + "create": "创建", + "tryToReconnect": "尝试连接", + "stayAnonymous": "Stay anonymous", + "authorize": "Authorize" + }, + "commonWords": { + "you": "你", + "send": "发送", + "or": "或者", + "of": "的", + "with": "以及", + "and": "和", + "on": "在", + "per": "每" + } +} \ No newline at end of file diff --git a/interface/i18n/mist.ca.i18n.json b/interface/i18n/mist.ca.i18n.json new file mode 100644 index 0000000..60e7670 --- /dev/null +++ b/interface/i18n/mist.ca.i18n.json @@ -0,0 +1,309 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "Sobre __app__", + "checkForUpdates": "Buscar actualitzacions...", + "checkForNodeUpdates": "Busca actualitzacions dels nodes d'Ethereum...", + "services": "Serveis", + "hide": "Hide __app__", + "hideOthers": "Ocultar els altres", + "showAll": "Mostrar tot", + "quit": "Sortir __app__" + }, + "file": { + "label": "Fitxer", + "importPresale": "Importa compte", + "newAccount": "Nou compte", + "backup": "Copia de seguretat", + "backupKeyStore": "Comptes", + "backupMist": "Dades de l'aplicació", + "swarmUpload": "Pujar a Swarm..." + }, + "edit": { + "label": "Editar", + "undo": "Desfer", + "redo": "Refer", + "cut": "Tallar", + "copy": "Copiar", + "paste": "Enganxar", + "selectAll": "Seleccionar tot" + }, + "view": { + "label": "Veure", + "fullscreen": "Commutar pantalla completa", + "languages": "Idioma", + "default": "Defecte", + "langCodes": { + "ca": "Català", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fa": "فارسى", + "fr": "Français", + "it": "Italiano", + "ja": "日本語", + "ko": "한국어 ", + "nl": "Nederlands", + "nb": "Norsk", + "pt": "Português", + "sq": "Shqip", + "ru": "Pусский", + "zh": "普通話", + "zh-TW": "國語" + } + }, + "develop": { + "label": "Desenvolupar", + "devTools": "Commutar eines de desenvolupador", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Wallet UI", + "devToolsWebview": "__webview__", + "runTests": "Executar tests", + "logFiles": "Mostrar fitxer de log", + "openRemix": "Obrir Remix IDE", + "externalNode": "utilitzar un node extern", + "ethereumNode": "Node d'Ethereum", + "network": "Xarxa", + "mainNetwork": "Xarxa Principal", + "nodeMode": "Descàrrega de la Cadena", + "fullNode": "Desar la blockchain completa", + "lightNode": "Utilitzar el Node lleuger (experimental!)", + "startMining": "⛏ Començar a minar (només Testnet)", + "stopMining": "⛏ Parar de minar" + }, + "window": { + "label": "Finestra", + "minimize": "Minimitza", + "close": "Tancar", + "toFront": "Portar tot al front" + }, + "help": { + "label": "Ajuda", + "discord": "Discord", + "reddit": "Reddit", + "reportBug": "Reportar un problema a Github" + } + }, + "errors": { + "nodeConnect": "No has pogut connectar al node? Mira els logs per més:", + "nodeStartup": "Sembla que el node no s'ha pogut iniciar. Ja en tens un executant-se? Està actualitzant la base de dades just ara?", + "timeSync": { + "title": "El rellotge de l'ordinador no està sincronitzat.", + "description": "Per estar del tot sincronitzat amb la xarxa Ethereum, necessites sincronitzar el rellotge del teu ordinador amb un servidor de sincronització.", + "win32": "Vés a les teves preferències del rellotge d'internet i marca la casella. Mira aquesta guia per tenir-ne més detalls: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "Per habilitar la sincronització del rellotge, instal·la \"ntp\" mitjançant \"apt-get install ntp\".", + "darwin": "Per habilitar la sincronització del rellotge, obre les preferències de Data i hora i activa \"Ajustar la data i l'hora automàticament\"." + }, + "nodeChecksumMismatch": { + "title": "La suma de verificació no coincideix amb el node descarregat!", + "description": "__algorithm__: __hash__\n\nSi us plau instal·la el __type__ node versió __version__ manualment." + }, + "legacyChain": { + "title": "Cadena 'legacy' detectada", + "description": "El teu node està actualment a la cadena d'Ethereum Classic. Per utilitzar aquesta cadena, utilitza les eines proporcionades pel projecte ethereum classic a\nhttps://ethereumclassic.github.io.\n\nPer canviar a la cadena principal d'ethereum segueix el aquest tutorial:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Recarregar", + "openDevTools": "Obre les eines de desenvolupador", + "inspectElements": "Inspecciona element" + }, + "nodeInfo": { + "nodeSyncing": "Resten __blockDiff__ blocs", + "blockReceived": "Nou bloc rebut", + "blockReceivedShort": "Nou bloc", + "blockNumber": "El teu últim número de bloc", + "timeSinceBlock": "Temps transcorregut des de l'últim bloc", + "checkingWhichNetwork": "Comprovant la xarxa...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "mainnetExplain": "Ets a la xarxa gobal d'Ethereum principal", + "testnetExplain": "Ets a la __name__. NO ENVIÏS cap Ether real a aquestes adreces", + "privatenetExplain": "Ets a la xara privada. NO ENVIÏS cap Ether real a aquestes adreces", + "unknownnetExplain": "Incapaç de determinar a quina xarxa ets", + "peers": "peers" + }, + "sidebar": { + "buttons": { + "browser": "Navega" + }, + "submenu": { + "account": "Compte", + "account_plural": "Comptes", + "connectAccounts": "Connectar Comptes" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "Comptes no establerts", + "connect": "Connectar" + } + }, + "startScreen": { + "runningNodeFound": "Trobat node d'Ethereum executant-se!", + "startingNode": "Iniciant node d'Ethereum...", + "stoppingNode": "Aturant node d'Ethereum...", + "startedNode": "Iniciant l'aplicació...", + "nodeConnectionTimeout": "No s'ha pogut iniciar el node d'Ethereum!
Si has instal·lat Geth, utilitza aquesta comanda per executar-lo:
geth --ipcpath __path__

O notifica l'error ", + "nodeBinaryNotFound": "No s'ha torbat el binari del node d'Ethereum!
Si us plau inicia'n un manualment primer. ", + "nodeStarting": "Node d'Ethereum iniciant-se...", + "nodeStarted": "Node d'Ethereum iniciat", + "nodeConnected": "Node d'Ethereum connectat", + "nodeStopping": "Ethereum node aturant-se...", + "nodeStopped": "Node d'Ethereum aturat", + "nodeError": "Error de connectivitat del node d'Ethereum:'(", + "unableToBindPort": "El node d'Ethereum no pot executar-se. N'hi ha alguna altra instància excutant-se?", + "nodeSyncing": "El node d'Ethereum necessita sincronitzar-se, si us plau espera...", + "nodeSyncInfo": "Descarregant bloc __displayBlock__ de __highestBlock__", + "nodeSyncInfoStates": "Descarregant bloc __displayBlock__ de __highestBlock__,
Descarregant l'estructura de la cadena __displayState__ de __displayKnownStates__", + "nodeSyncConnecting": "Cercant peers...", + "nodeSyncFoundPeers": "Connectant amb __peers__ peers...", + "peerSearchTimeout": "Passar cerca de peers", + "launchApp": "Iniciar Aplicació", + "clientBinaries": { + "scanning": "Comprovant actualitzacions del node...", + "downloading": "Descarregant un nou node...", + "loadConfig": "Carregant configuració del client...", + "filtering": "Filtrant binaris del client...", + "done": "Node d'Ethereum actualitzat...", + "error": "Error executant el binari descarregat." + } + }, + "popupWindows": { + "updateAvailable": { + "newVersionAvailable": "Nova __name__ versió disponible", + "version": "Versió", + "downloadURL": "URL de descàrrega", + "checksum": "Checksum", + "downloadAndRestart": "Actualitza i Reinicia", + "download": "Descarrega la nova versió", + "skipUpdate": "Omet l'actualització", + "notNow": "Pregunta-m'ho després", + "checking": "Comprovant actualitzacions a __name__...", + "noUpdateFound": "No s'ha trobat cap actualització. Estàs executant l'última versió de __name__." + }, + "requestAccount": { + "title": "Crear un compte", + "enterPassword": "Introdueix una contrasenya", + "repeatPassword": "Repeteix la contrasenya", + "creating": "Generant el compte...", + "backupHint": "Assegura't que fas una còpia de seguretat dels teus fitxer de claus I contrasenya!\n\nPots trobar el teu fitxer de claus mitjançant el menú principal -> Fitxer -> Copia de seguretat -> Comptes. Desa una copia de la carpeta del \"fitxer de claus\" on no puguis perdre-la!", + "errors": { + "passwordMismatch": "Les teves contrasenyes no coincideixen.", + "passwordTooShort": "Utilitza una contrasenya més llarga" + } + }, + "unlockMasterPassword": { + "title": "Introdueix una contrasenya mestra", + "enterPassword": "Introdueix contrasenya mestra", + "unlocking": "Desbloquejant...", + "errors": { + "wrongPassword": "La contrasenya és incorrecta. Torna-ho a provar." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Enviar transacció", + "contractExecution": "Executar contracte", + "createContract": "Crear contracte" + }, + "contractExecutionInfo": "Estàs a punt d'executar una funció d'un contracte. Això podria implicar una transferència de valor.", + "contractCreationInfo": "Estàs a punt de crear un contracte de les dades proporcionades.", + "enterPassword": "Introdueix la contrasenya per confirmar la transacció", + "unlocking": "Confirmant...", + "createContract": "Crear contracte", + "estimatedFee": "Comissió estimada", + "estimatedGasError": "Sembla que la transacció fallarà. Si l'envieu, pot consumir tot el gas proporcionat.", + "transactionThrow": "El contracte no et permetrà executar aquesta transacció", + "overBlockGasLimit": "El gas necesàri per aquesta execució pot sobrepassar el limit de gas pel bloc.", + "notEnoughGas": "El gas pot no ser suficient per acabar aquesta execució amb èxit.
Fés clic aquí per augmentar la quantitat de gas.", + "noEstimate": "No s'ha pogut calcular el gas necessari.", + "gasPrice": "Preu del Gas", + "perMillionGas": "ether per un milió de gas", + "gasLimit": "Proporciona la comissió màxima", + "data": "Dades en brut", + "parameters": "Paràmetres", + "buttons": { + "sendTransaction": "Enviar transacció" + }, + "errors": { + "connectionTimeout": "No s'ha pogut connectar al node, ha fallat la tasca al fons?", + "wrongPassword": "Contrasenya errònia", + "multipleKeysMatchAddress": "Multiples claus coincideixen amb l'adreça. Si us plau eliminar els duplicats del fitxer de claus (menú -> Fitxer -> Copia de seguretat -> Comptes)", + "insufficientFundsForGas": "Saldo insuficient al compte principal (etherbase) per pagar el gas", + "sameAccount": "No es pot enviar a un mateix" + }, + "showRawBytecode": "mostrar dades en brut", + "showDecodedParameters": "mostra els paràmetres descodificats", + "lookupData": "Intentar descodificar les dades", + "lookupDataExplainer": "Mira això a internet" + }, + "onboarding": { + "description": "Ethereum és una plataforma per aplicacions descentralitzades de la blockchain amb un llenguatge de programació complet", + "goToTestnet": "Utilitza la xarxa de test (Rinkeby)", + "goToTestnetDescription": "Prova la tecnologia lliurement a la xarxa de test 'sandboxed', sembla utilitzar Ether real.", + "gotoMainnet": "Utilitza la xarxa principal", + "gotoMainnetDescription": "Necessitaràs Ether per crear i executar contractes. No et preocupis, t'ajudarem a aconseguir-ne una mica...", + "doYouHaveAWalletFile": "Tens un fitxer de wallet?", + "walletFileDescription": "

Mou qualsevol wallet aquí per a importar-lo.
Si va participar a la Pre-venda d'Ethereum el 2014, hauries de tenir un fitxer anomenat ethereum_wallet_backup.json. El vas poder descarregar després de la venda i també se't va enviar al teu email

", + "dropFilesHere": "Deixa anar el fitxer de wallet", + "creating": "Creant...", + "importing": "Important...", + "skip": "Saltar aquest pas", + "next": "Següent", + "protectTitle": "Protegeix el teu compte", + "protectDescription": "Escull una contrasenya pel teu nou compte. Assegura't que és tant fort com si hagués de protegir les claus de casa teva!", + "accountTitle": "Carrega'l!", + "accountTitleTestnet": "Minar una mica!", + "etherDescription": "La xarxa d'ethereum es basa en un token anomenat “Ether”. En necessitaràs una petita quantitat per fer qualsevol cosa a la xarxa d'Ethereum.", + "loadItDescription": "Si ja tens Bitcoin, o qualsevol altra criptomoneda, pots canviar-la a Ether fàcilment utilitzant changelly.

Et recomanem carregar entre 0.25 i 1 Ether.", + "faucetDescription": "La xarxa de test Rinkeby utilitza 'Clique Proof of Authority' com a mecanisme de consens, pertant no hi ha minat. Si vols obtenir una mica d'ether de prova, vés a la Rinkeby Faucet: faucet.rinkeby.io ", + "you": "TU", + "etherbase": "Compte principal (etherbase)", + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "learnIt": "Aprèn mentre esperes", + "downloadingBlocks": "Descarregant blocs", + "syncMessage": "Bloc __displayBlock__ de __highestBlockString__", + "syncMessageWithStates": "Bloc __displayBlock__ de __highestBlockString__ (Estructura de cadena __statesPercent__%)", + "startingSync": "Preparant-se per sinc..", + "tutorial1Description": "

Ara l'última cosa que queda és esperar que la descàrrega acabi. Aquí tens alguna lectura suggerida:

Crea els teu propis diners

Crea una criptomoneda amb una quantitat fixa, tokens representant actius reals, etc.

", + "tutorial2Description": "

Crea una venda a multituds

Aixeca capital per un objectiu comú, absolutament confiable sense tercers. Evita l'obstacle del finançament tradicional i vés directament a l'origen finançant una organització mitjançant la blockchain.

", + "tutorial3Description": "

Crea una organització a la blockchain

Crea una organització autònoma amb normes de com es gasten els diners i es prenen les decisions per tu i els teus inversors.

", + "buttons": { + "showPassword": "Mostra la contrasenya", + "importAccount": "Importar compte", + "launchApp": "Llança l'aplicació!", + "learnReceipt": "Aprèn aquesta recepta" + }, + "errors": { + "nodeNotStartedYet": "Espera uns quants segons més fins que el teu node s'hagi iniciat completament i torna-ho a provar", + "unknownFile": "Fitxer no reconegut.", + "wrongPassword": "Contrasenya incorrecta.", + "importFailed": "No s'ha pogut importar el fitxer, s'ha obtingut l'error: __error__" + } + }, + "connectAccount": { + "chooseAccountTitle": "Escull compte", + "createAccount": "Crea un nou compte", + "pinToSidebar": "Fixa app a la barra lateral", + "connectAccountDescription": "Estàs compartint la teva identitat amb __dappName__. Això permet a la app veure qualsevol informació pública rellevant relacionada amb els teus comptes, incloent els saldos." + } + } + }, + "elements": { + "checksumAlert":"Aquesta adreça sembla vàlida, però no té mesures de seguretat que ajuden a no equivocar-te errors tipogràfics, re-comprova que és la correcta. Si pots, comprova que la icona de seguretat coincideix.", + "identiconHelper": "Aquesta és la icona de seguretat. Si hi hagués cap canvi a l'adreça, la icona seria una completament diferent", + "type": { + "address": "Adreça", + "bool": "Booleà", + "int": "Enter", + "uint": "Nombre Natural", + "string": "Cadena", + "bytes": "Octets" + } + } +} diff --git a/interface/i18n/mist.de.i18n.json b/interface/i18n/mist.de.i18n.json new file mode 100644 index 0000000..84fc92b --- /dev/null +++ b/interface/i18n/mist.de.i18n.json @@ -0,0 +1,281 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "Über __app__", + "checkForUpdates": "Nach Aktualisierungen suchen...", + "checkForNodeUpdates": "Nach Ethereum Softwareknoten Aktualisierungen suchen...", + "services": "Dienste", + "hide": "__app__ ausblenden", + "hideOthers": "Andere ausblenden", + "showAll": "Alle einblenden", + "quit": "__app__ schließen" + }, + "edit": { + "label": "Bearbeiten", + "undo": "Rückgängig", + "redo": "Wiederholen", + "cut": "Ausschneiden", + "copy": "Kopieren", + "paste": "Einfügen", + "selectAll": "Alles auswählen" + }, + "view": { + "label": "Ansicht", + "fullscreen": "Vollbildmodus", + "default": "Standard" + }, + "file": { + "label": "Datei", + "importPresale": "Konto importieren", + "newAccount": "Neues Konto", + "backup": "Sicherung", + "backupKeyStore": "Konten", + "backupMist": "Anwendungsdaten" + }, + "develop": { + "uploadToSwarm": "Upload zum Swarm", + "label": "Entwicklung", + "devTools": "Entwicklerwerkzeuge", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Wallet UI", + "devToolsWebview": "__webview__", + "runTests": "Tests durchführen", + "logFiles": "Logdatei anzeigen", + "openRemix": "Remix IDE öffnen", + "ethereumNode": "Ethereum Softwareknoten", + "network": "Netzwerk", + "mainNetwork": "Hauptnetzwerk", + "startMining": "⛏ Mining starten", + "stopMining": "⛏ Mining stoppen", + "externalNode": "externer Softwareknoten aktiv", + "nodeMode": "Chain herunterladen", + "fullNode": "Komplette Blockchain speichern", + "lightNode": "Light Node speichern (experimentell!)" + }, + "window": { + "label": "Fenster", + "minimize": "Minimieren", + "close": "Schließen", + "toFront": "Alle Fenster in den Vordergrund" + }, + "help": { + "label": "Hilfe", + "reportBug": "Ein Problem melden" + } + }, + "errors": { + "nodeConnect": "Es konnte keine Verbindung mit dem Softwareknoten hergestellt werden. Weitere Informationen finden sich in den Logdateien.", + "nodeStartup": "Anscheinend konnte der Softwareknoten nicht gestartet werden, läuft evtl. schon eine andere Instanz? Oder läuft eventuell gerade ein Datenbank-Update?", + "timeSync": { + "title": "Deine Computeruhr ist nicht synchronisiert!", + "description": "Um mit dem Ethereum-Netzwerk zu synchronisieren muss deine Computeruhr mit einem Zeitserver synchronisiert werden.", + "win32": "Gehe dazu in deine Internet Zeit Einstellungen in deinen System Einstellungen and checke die Box. Siehe diese Anleitung für Details: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "Um Zeit Synchronisation einzuschalten installiere \"ntp\" via \"apt-get install ntp\".", + "darwin": "Um Zeit Synchronisation einzuschalten, öffne die System Einstellungen und checke \"Zeit Datum automatisch\"." + }, + "nodeChecksumMismatch": { + "title": "Prüfsumme des heruntergeladenen Softwareknotens stimmt nicht überein!", + "description": "__algorithm__: __hash__\n\nBitte installiere den Softwareknoten __type__ in Version __version__ manuell." + }, + "legacyChain": { + "title": "Veraltete Chain erkannt", + "description": "Dein Softwareknoten ist zur Zeit auf der nicht unterstützten Ethereum Classic Chain. Um diese Chain zu nutzen, verwende die Tools vom Ethereum Classic Project unter\nhttps://ethereumclassic.github.io.\n\nUm zur Hauptchain von Ethereum zurückzukehren, folge den Schritten in diesem Tutorial:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Neu laden", + "openDevTools": "Entwicklerwerkzeuge öffnen", + "inspectElements": "Element prüfen" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ Blöcke übrig", + "blockReceived": "Neuer Block empfangen", + "timeSinceBlock": "Abgelaufene Zeit seit dem letzten Block", + "blockNumber": "Ihre letzte Blocknummer", + "testnetExplain": "Du bist mit dem Testnetz verbunden, SENDE KEINE echten Ether an diese Adressen", + "peers": "Peers", + "checkingWhichNetwork": "Überprüfe Netzwerk...", + "mainNetwork": "Hauptnetzwerk", + "testNetwork": "Testnetzwerk", + "privateNetwork": "Privates Netzwerk", + "mainnetExplain": "Du bist mit dem globalen Hauptnetz von Ethereum verbunden", + "privatenetExplain": "Du bist mit einem privaten Netz verbunden, SENDE KEINE echten Ether an diese Adressen", + "unknownnetExplain": "Es konnte nicht bestimmt werden, welches Netzwerk du nutzt" + }, + "sidebar": { + "buttons": { + "browser": "Browser" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "Keine Konten vorhanden", + "connect": "Verbinden" + } + }, + "startScreen": { + "runningNodeFound": "Laufender Ethereum Softwareknoten gefunden!", + "startingNode": "Starte Ethereum Softwareknoten...", + "startedNode": "Starte Anwendung...", + "nodeConnectionTimeout": "Ethereum Softwareknoten konnte nicht gestartet werden!
Wenn du Geth installiert hast,, verwende bitte diesen Befehl, um Geth zu starten:
geth --ipcpath __path__

oder sende einen Fehlerreport", + "nodeBinaryNotFound": "Keine Programmdatei für den Ethereum Softwareknoten gefunden!
Bitte starte den Ethereum Softwareknoten manuell. ", + "nodeSyncing": "Ethereum Softwareknoten muss synchronisieren, bitte warten...", + "nodeSyncInfo": "Block __displayBlock__ von __highestBlock__ wird heruntergeladen.", + "nodeSyncConnecting": "Suche nach Peers...", + "peerSearchTimeout": "Peer-Suche überspringen", + "stoppingNode": "Stoppe Ethereum Softwareknoten...", + "nodeStarting": "Ethereum Softwareknoten startet...", + "nodeStarted": "Ethereum Softwareknoten gestartet", + "nodeConnected": "Ethereum Softwareknoten verbunden", + "nodeStopping": "Ethereum Softwareknoten stoppt...", + "nodeStopped": "Ethereum Softwareknoten gestoppt", + "nodeError": "Verbindungsproblem zum Ethereum Softwareknoten :'(", + "unableToBindPort": "Ethereum Softwareknoten kann nicht gestartet werden. Läuft bereits eine andere Instanz?", + "nodeSyncInfoStates": "Lade Block __displayBlock__ von __highestBlock__,
Lade chain structure __displayState__ von __displayKnownStates__", + "nodeSyncFoundPeers": "Verbinde mit __peers__ Peers...", + "launchApp": "Starte die Anwendung", + "clientBinaries": { + "scanning": "Suche nach Softwareknoten Aktualisierung...", + "downloading": "Lade neue Softwareknoten-Version herunter...", + "loadConfig": "Lade Softwareknoten Konfiguration...", + "filtering": "Filtering client binaries...", + "done": "Ethereum Softwareknoten aktuell...", + "error": "Ethereum Softwareknoten konnte nicht gestartet werden." + } + }, + "popupWindows": { + "requestAccount": { + "title": "Konto anlegen", + "enterPassword": "Passwort eingeben", + "repeatPassword": "Passwort wiederholen", + "creating": "Konto wird angelegt...", + "backupHint": "Bitte stelle sicher dass du von allen Schlüsseldateien Sicherungen erstellst. Unabhängig davon solltest du dich AUCH vergewissern dass du deine Passwörter nicht vergisst bzw. dass du diese sicher in einem Passwort-Manager abgespeichert hast!\n\nDie verschlüsselten Wallet-Dateien findest du im Hauptmenü -> Datei -> Sicherung -> Konten. Bewahre Kopien des \"keystore\" Ordners an einem sicheren Ort auf!", + "errors": { + "passwordMismatch": "Die Passwörter stimmen nicht überein.", + "passwordTooShort": "Wähle ein längeres Passwort..." + } + }, + "unlockMasterPassword": { + "title": "Master-Passwort eingeben", + "enterPassword": "Gib das Master-Passwort ein", + "unlocking": "Entschlüsseln...", + "errors": { + "wrongPassword": "Passwort falsch, bitte nochmals versuchen." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Transaktion senden", + "contractExecution": "Vertrag ausführen", + "createContract": "Vertrag anlegen" + }, + "contractExecutionInfo": "Du bist dabei, eine Vertragsfunktion auszuführen. Das kann zur Übertragung eines Geldwertes führen.", + "contractCreationInfo": "Du bist dabei, auf Basis der eingegebenen Daten einen Vertrag anzulegen.", + "enterPassword": "Bitte gib das Passwort ein, um die Transaktion durchzuführen.", + "unlocking": "Warten auf Bestätigung...", + "createContract": "Vertrag anlegen", + "estimatedFee": "Geschätzter Gebührenbetrag", + "estimatedGasError": "Der Auftrag kann nicht ausgeführt werden, da er das gesamte vorgegebene Gas verbrauchen würde.", + "gasPrice": "Gaspreis", + "perMillionGas": "Ether pro Millionen Gas", + "data": "Daten", + "buttons": { + "sendTransaction": "Transaktion absenden" + }, + "errors": { + "connectionTimeout": "Eine Verbindung mit dem Softwareknoten war nicht möglich, eventuell ist der Softwareknoten im Hintergrund abgestürzt?", + "wrongPassword": "Falsches Passwort", + "multipleKeysMatchAddress": "Mehrere Konten stimmen mit der Adresse überein, bitte entferne Duplikate aus dem keystore Verzeichnis (Menü -> Datei -> Sicherung -> Konten)", + "insufficientFundsForGas": "Zu wenig Mittel im Hauptkonto (etherbase) um für Gas zu bezahlen", + "sameAccount": "Kann nicht zum gleichen Konto schicken." + }, + "transactionThrow": "Der Vertrag wird diese Transaktion nicht ausführen können", + "noEstimate": "Transaktionsgebühr konnte nicht geschätzt werden.", + "gasLimit": "Maximal bereitgestellte Gebühr", + "parameters": "Parameter", + "showRawBytecode": "Zeige Rohdaten", + "showDecodedParameters": "Zeige dekodierte Parameter", + "lookupData": "Versuche die Daten zu dekodieren", + "lookupDataExplainer": "Schaue dies im Internet nach" + }, + "onboarding": { + "description": "Ethereum ist eine dezentrale Plattform, um Anwendungen auf einer Blockchain zu bauen: Fälschungssichere Software, die Werte und Vermögen übertragen kann und für immer besteht", + "goToTestnet": "Verwende das Testnetz (Rinkeby)", + "goToTestnetDescription": "Teste die Technologie frei in der Testnetz-Sandbox, ", + "gotoMainnet": "Verwende das Hauptnetz", + "gotoMainnetDescription": " Du wirst etwas Ether benötigen, um Verträge anzulegen und auszuführen. Wir werden dir helfen, etwas zu bekommen ...", + "doYouHaveAWalletFile": "Hast du eine Wallet-Datei?", + "walletFileDescription": "

Wallet-Datei zum importieren in dieses Fenster ziehen.
Wenn du 2014 am Ethereum-Pre-sale teilgenommen hast, solltest du über eine Datei mit dem Dateinamen ethereum_wallet_backup.json verfügen. Sie wurde nach dem Kauf heruntergeladen und dir auch per E-Mail geschickt.

", + "dropFilesHere": "Pre-sale Datei laden", + "creating": "Erstellen...", + "importing": "Importieren...", + "skip": "Diesen Schritt überspringen", + "next": "Nächster", + "protectTitle": "Schütze dein Konto", + "protectDescription": "Wähle ein Passwort für dein Konto. Mache es so stark, als wären es deine Hausschlüssel!", + "accountTitle": "Lade die Datei hoch!", + "accountTitleTestnet": "Ether minen!", + "etherDescription": "Das Ethereum Netz basiert auf einem Tokan namens “Ether”. Du benötigst eine kleine Menge davon, um irgendetwas auf dem Ethereum-Netz zu tun.", + "loadItDescription": "Wenn du bereits über Bitcoin oder eine andere Kryptowährung verfügst, kannst du diese mit changelly einfach in Ether umtauschen.

Wir empfehlen, ca. 0.25 bis 1 ether einzutauschen.", + "mineItDescription": "Auf dem Testnetz kannst du selbst Ether minen. Bitte gehe dazu in den Menüpunkt Entwicklung menu und wähle Mining starten.
VERSUCHE NICHT, ECHTE ETHER AN DIESE ADRESSE ZU SENDEN! ", + "you": "DU", + "etherbase": "Hauptkonto (etherbase)", + "depositBitcoin": "Bitcoin eintauschen", + "learnIt": "Lerne Ethereum kennen, während du wartest", + "downloadingBlocks": "Blöcke werden heruntergeladen", + "tutorial1Description": "

Nun musst du lediglich warten, bis der Download abgeschlossen ist. Hier findest du weitere Informationen:

Make your own money

Erstelle eine eigene Kryptowährung mit einer festen Geldmenge, Token, die reale Vermögenswerte darstellen, und so weiter ...

", + "tutorial2Description": "

Erstelle einen Crowdsale

Sammle Mittel für ein gemeinsames Ziel, vollkommen vertrauenswürdig ohne einen weiteren Dritten. Überwinde die Hürden von traditionellen Crowdfunding-Systemen und gehe direkt an die Quellen, indem du deine Organisation über die Blockchain mit Mitteln versorgst.

", + "tutorial3Description": "

Blockchain-Organisation

Schaffe eine autonome Organisation, deren Grundsätze über Geldverwendung und Entscheidungen nicht gebrochen werden können. Gib deinen Unterstützern eine aktive Rolle, wie die Mittel verwendet werden sollen

", + "buttons": { + "showPassword": "Passwort anzeigen", + "importAccount": "Konto importieren", + "launchApp": "Anwendung wird gestartet!", + "learnReceipt": "Lerne dieses Rezept kennen" + }, + "errors": { + "nodeNotStartedYet": "Warte noch einige Sekunden, bis der Softwareknoten gestartet ist, und versuche es dann noch einmal", + "unknownFile": "Datei nicht erkannt.", + "wrongPassword": "Falsches Passwort.", + "importFailed": "Beim Import der Datei ist folgender Fehler aufgetreten: __error__" + }, + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "syncMessage": "Block __displayBlock__ von __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ von __highestBlockString__ (Chain Struktur __statesPercent__%)", + "startingSync": "Bereite Synchronisation vor.." + }, + "updateAvailable": { + "newVersionAvailable": "Neue __name__ Version verfügbar", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Prüfsumme", + "downloadAndRestart": "Update und Neustart", + "download": "Neue Version herunterladen", + "skipUpdate": "Update überspringen", + "notNow": "Später erinnern", + "checking": "Suche nach Updates für __name__...", + "noUpdateFound": "Kein Update gefunden. Du verwendest die aktuellste Version von __name__." + }, + "connectAccount": { + "chooseAccountTitle": "Wähle ein Konto", + "createAccount": "Erstelle ein neues Konto", + "pinToSidebar": "App an die Seitenleiste pinnen", + "connectAccountDescription": "Du teilst deine Identität mit __dappName__. Das erlaubt der App jegliche öffentliche Informationen deiner Konten sowie den damit verbundenen Bilanzen zu sehen." + } + } + }, + "elements": { + "checksumAlert": "Diese Adresse sieht gültig aus, aber ihr fehlen einige Sicherheits-Features, die dich z.B. gegen Tippfehler schützen könnten. Bitte prüfe daher nochmals, ob du die Adresse richtig eingegeben hast. Sofern vorhanden, prüfe bitte auch, ob das Sicherheits-Icon übereinstimmt. ", + "identiconHelper": "Dies ist ein Sicherheits-Icon. Bei einer abweichenden Adresse sollte das Sicherheits-Icon völlig anders aussehen.", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.en.i18n.json b/interface/i18n/mist.en.i18n.json new file mode 100644 index 0000000..d641bca --- /dev/null +++ b/interface/i18n/mist.en.i18n.json @@ -0,0 +1,313 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "About __app__", + "checkForUpdates": "Check for updates...", + "checkForNodeUpdates": "Check for EtherCore node updates...", + "services": "Services", + "hide": "Hide __app__", + "hideOthers": "Hide others", + "showAll": "Show all", + "quit": "Quit __app__" + }, + "file": { + "label": "File", + "importPresale": "Import accounts", + "newAccount": "New account", + "backup": "Backup", + "backupKeyStore": "Accounts", + "backupMist": "Application data", + "swarmUpload": "Upload to Swarm..." + }, + "edit": { + "label": "Edit", + "undo": "Undo", + "redo": "Redo", + "cut": "Cut", + "copy": "Copy", + "paste": "Paste", + "selectAll": "Select all" + }, + "view": { + "label": "View", + "fullscreen": "Toggle full screen", + "languages": "Language", + "default": "Default", + "langCodes": { + "ca": "Català", + "de": "Deutsch", + "en": "English", + "es": "Español", + "fa": "فارسى", + "fr": "Français", + "it": "Italiano", + "ja": "日本語", + "ko": "한국어 ", + "nl": "Nederlands", + "nb": "Norsk", + "pt": "Português", + "sq": "Shqip", + "ru": "Pусский", + "zh": "普通話", + "zh-TW": "國語" + } + }, + "develop": { + "label": "Develop", + "devTools": "Toggle developer tools", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Wallet UI", + "devToolsWebview": "__webview__", + "runTests": "Run tests", + "logFiles": "Show log files", + "openRemix": "Open Remix IDE", + "ethereumNode": "EtherCore Node", + "network": "Network", + "mainNetwork": "Main Network", + "nodeMode": "Chain download", + "fullNode": "Store full blockchain", + "lightNode": "Use light Node (experimental!)", + "startMining": "⛏ Start mining", + "stopMining": "⛏ Stop mining", + "enableSwarm": "Enable Swarm" + }, + "window": { + "label": "Window", + "minimize": "Minimize", + "close": "Close", + "toFront": "Bring all to front" + }, + "help": { + "label": "Help", + "discord": "Discord", + "reddit": "Reddit", + "reportBug": "Report an issue on Github" + } + }, + "errors": { + "nodeConnect": "Couldn't connect to node? See the logs for more:", + "nodeStartup": "It seems like the node couldn't be started. Do you already have one running? Is it upgrading the database right now?", + "timeSync": { + "title": "Your computer's clock is not synced.", + "description": "To successfully synchronize with the EtherCore network, you need to sync your computer's clock with a time sync server.", + "win32": "Go to your Internet Time Settings in your system preferences and check the box. See this guide for details: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "To enable a time sync server, install \"ntp\" via \"apt-get install ntp\".", + "darwin": "To enable time sync, open the time preferences and check \"Set the time and date automatically\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in downloaded node!", + "description": "__algorithm__: __hash__\n\nPlease install the __type__ node version __version__ manually." + }, + "legacyChain": { + "title": "Legacy chain detected", + "description": "Your node is currently on the unsupported Ethereum Classic chain. To use this chain, use tools provided by the ethereum classic project at\nhttps://ethereumclassic.github.io.\n\nTo revert to the main ethereum chain follow the tutorial here:\nhttps://github.com/ethereum/mist/releases/0.8.2" + }, + "swarm": { + "notEnabled": "Swarm is not enabled. Please enable it in the menu under Develop > Enable Swarm." + } + }, + "rightClick": { + "reload": "Reload", + "openDevTools": "Open developer tools", + "inspectElements": "Inspect element" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ blocks left", + "blockReceived": "New block received", + "blockReceivedShort": "New block", + "blockNumber": "Your latest block number", + "timeSinceBlock": "Elapsed time since last block", + "checkingWhichNetwork": "Checking network...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "mainnetExplain": "You are on the main EtherCore global network", + "testnetExplain": "You are on the __name__. DO NOT SEND any real ERE to these addresses", + "privatenetExplain": "You are on a private net. DO NOT SEND any real ERE to these addresses", + "unknownnetExplain": "Unable to determine which network you are on", + "peers": "peers" + }, + "sidebar": { + "buttons": { + "browser": "Browse" + }, + "submenu": { + "account": "Account", + "account_plural": "Accounts", + "connectAccounts": "Connect Accounts" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "No accounts set", + "connect": "Connect" + } + }, + "startScreen": { + "runningNodeFound": "Found running EtherCore node!", + "startingNode": "Starting EtherCore node...", + "stoppingNode": "Stopping EtherCore node...", + "startedNode": "Starting application...", + "nodeConnectionTimeout": "Couldn't start EtherCore node!
If you installed Geth, use this command to run it:
geth --ipcpath __path__

Or report an issue ", + "nodeBinaryNotFound": "No EtherCore node binary found!
Please start one manually before. ", + "nodeStarting": "EtherCore node starting up...", + "nodeStarted": "EtherCore node started", + "nodeConnected": "EtherCore node connected", + "nodeStopping": "EtherCore node stopping...", + "nodeStopped": "EtherCore node stopped", + "nodeError": "EtherCore node connection error:'(", + "unableToBindPort": "EtherCore node cannot run. Is another instance already running?", + "nodeSyncing": "EtherCore node needs to sync, please wait...", + "nodeSyncInfo": "Downloading block __displayBlock__ of __highestBlock__", + "nodeSyncInfoStates": "Downloading block __displayBlock__ of __highestBlock__,
Downloading chain structure __displayState__ of __displayKnownStates__", + "nodeSyncConnecting": "Looking for peers...", + "nodeSyncFoundPeers": "Connecting to __peers__ peers...", + "peerSearchTimeout": "Skip peer search", + "launchApp": "Launch Application", + "retryConnection": "Retry Connection", + "clientBinaries": { + "scanning": "Checking for node update...", + "downloading": "Downloading new node...", + "loadConfig": "Loading client config...", + "filtering": "Filtering client binaries...", + "done": "EtherCore node up-to-date...", + "error": "Error running downloaded binary." + } + }, + "popupWindows": { + "updateAvailable": { + "newVersionAvailable": "New __name__ version available", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Update and Restart", + "download": "Download new version", + "skipUpdate": "Skip Update", + "notNow": "Ask me later", + "checking": "Checking for updates to __name__...", + "noUpdateFound": "No update found. You are running the latest version of __name__." + }, + "requestAccount": { + "title": "Create account", + "enterPassword": "Enter password", + "repeatPassword": "Repeat password", + "creating": "Generating account...", + "backupHint": "Make sure you backup your keyfiles AND password!\n\nYou can find your keyfiles folder using the main menu -> File -> Backup -> Accounts. Keep a copy of the \"keystore\" folder where you can't lose it!", + "errors": { + "passwordMismatch": "Your passwords don't match.", + "passwordTooShort": "Make a longer password" + } + }, + "unlockMasterPassword": { + "title": "Enter master password", + "enterPassword": "Enter master password", + "unlocking": "Unlocking...", + "errors": { + "wrongPassword": "Password is wrong. Try again." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Send transaction", + "contractExecution": "Execute contract", + "createContract": "Create contract" + }, + "contractExecutionInfo": "You are about to execute a function on a contract. This might involve transfer of value.", + "contractCreationInfo": "You are about to create a contract from the provided data.", + "enterPassword": "Enter password to confirm the transaction", + "unlocking": "Confirming...", + "createContract": "Create contract", + "estimatedFee": "Estimated fee consumption", + "estimatedGasError": "It seems this transaction will fail. If you submit it, it may consume all the gas you provide.", + "transactionThrow": "The contract won't allow this transaction to be executed", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount.", + "noEstimate": "We couldn't estimate the gas.", + "gasPrice": "Gas price", + "perMillionGas": "ERE per million gas", + "gasLimit": "Provide maximum fee", + "data": "Raw Data", + "parameters": "Parameters", + "buttons": { + "sendTransaction": "Send transaction" + }, + "errors": { + "connectionTimeout": "Couldn't connect to the node, did it crash in the background?", + "wrongPassword": "Wrong password", + "multipleKeysMatchAddress": "Multiple keys match address. Please remove duplicates from keystore (menu -> File -> Backup -> Accounts)", + "insufficientFundsForGas": "Insufficient funds in main account (etherbase) to pay for gas", + "sameAccount": "Can't send to itself" + }, + "showRawBytecode": "show raw data", + "showDecodedParameters": "show decoded parameters", + "lookupData": "Try to decode data", + "lookupDataExplainer": "Look this up on the internet" + }, + "onboarding": { + "description": "EtherCore is a platform for decentralized blockchain apps with a fully featured programming language", + "goToTestnet": "Use the test network", + "goToTestnetDescription": "Test the technology freely in a sandboxed testnet, without using real ERE.", + "gotoMainnet": "Use the main network", + "gotoMainnetDescription": "You’ll need some ERE to create and execute contracts. Don't worry, we'll help you get some...", + "doYouHaveAWalletFile": "Do you have a wallet file?", + "walletFileDescription": "

Move any wallet file here to import.

", + "dropFilesHere": "Drop wallet file", + "creating": "Creating...", + "importing": "Importing...", + "skip": "Skip this step", + "next": "Next", + "protectTitle": "Protect your account", + "protectDescription": "Choose a password for your new account. Make it as strong as if it were to protect your house keys!", + "accountTitle": "Load it up!", + "accountTitleTestnet": "Mine some!", + "etherDescription": "The EtherCore network is based on a token called “Ether”. You’ll need a small amount of it to do anything on the Ethereum network.", + "loadItDescription": "If you already own Bitcoin, or any other cryptocurrency, you can easily convert it to ether using changelly.

We recommend loading somewhere between $1 - $10 in ether.", + "faucetDescription": "The Rinkeby testnet uses Clique Proof of Authority as a consensus mechanism, therefore there's no mining. If you want to get some test ether, head to the Rinkeby Faucet: faucet.rinkeby.io ", + "you": "YOU", + "etherbase": "Main account", + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "learnIt": "Learn while you wait", + "downloadingBlocks": "Downloading blocks", + "syncMessage": "Block __displayBlock__ of __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ of __highestBlockString__ (Chain structure __statesPercent__%)", + "startingSync": "Getting ready to sync..", + "tutorial1Description": "

Now the only thing left to do is wait for the download to finish. Here are some reading suggestions:

Make your own money

Make a cryptocurrency with a fixed market supply, tokens representing real world assets, etc

", + "tutorial2Description": "

Create a crowdsale

Raise funds for a common goal, fully trustable without a third party. Sidestep the hurdle of traditional funding system and go directly to the source by funding an organization via the blockchain.

", + "tutorial3Description": "

Create a blockchain organization

Create an autonomous organization with rules on spending money and making decisions for you and your investors.

", + "buttons": { + "showPassword": "Show password", + "importAccount": "Import account", + "launchApp": "Click To Start!!!", + "learnReceipt": "Learn this recipe" + }, + "errors": { + "nodeNotStartedYet": "Wait a few more seconds until your node is fully started and try again", + "unknownFile": "File not recognised.", + "wrongPassword": "Wrong password.", + "importFailed": "Couldn't import the file, got: __error__" + } + }, + "connectAccount": { + "chooseAccountTitle": "Choose account", + "createAccount": "Create new account", + "pinToSidebar": "Pin app to the sidebar", + "connectAccountDescription": "You are sharing your identity with __dappName__. This allows the app to see any public information related to your accounts, including balances connected to it." + } + } + }, + "elements": { + "checksumAlert":"This address looks valid, but it doesn't have some security features that will protect you against typos, so double check you have the right one. If provided, check if the security icon matches.", + "identiconHelper": "This is a security icon. If there were any change to the address, the resulting icon would be a completely different one", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.es.i18n.json b/interface/i18n/mist.es.i18n.json new file mode 100644 index 0000000..1f18641 --- /dev/null +++ b/interface/i18n/mist.es.i18n.json @@ -0,0 +1,283 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "Sobre __app__", + "checkForUpdates": "Buscar actualización...", + "checkForNodeUpdates": "Check for Ethereum node updates...", + "services": "Servicios", + "hide": "Ocultar __app__", + "hideOthers": "Ocultar otros", + "showAll": "Mostrar todo", + "quit": "Dejar __app__" + }, + "edit": { + "label": "Editar", + "undo": "Deshacer", + "redo": "Rehacer", + "cut": "Cortar", + "copy": "Copiar", + "paste": "Pegar", + "selectAll": "Seleccionar todo" + }, + "view": { + "label": "Ver", + "fullscreen": "Pantalla Completa", + "default": "Default" + }, + "file": { + "label": "Archivo", + "importPresale": "Importar Cuentas", + "newAccount": "Nueva cuenta", + "backup": "Copia de seguridad", + "backupKeyStore": "Cuentas", + "backupMist": "Datos de la aplicación", + "swarmUpload": "Subir a Swarm" + }, + "develop": { + "uploadToSwarm": "Upload a Swarm", + "label": "Desarrollo", + "devTools": "Herramientas para desarrolladores", + "devToolsMistUI": "UI de Mist", + "devToolsWalletUI": "UI del monedero", + "devToolsWebview": "__webview__", + "runTests": "Ejecutar pruebas", + "logFiles": "Mostrar archivo de registro", + "ethereumNode": "Nodo de Ethereum", + "network": "Red", + "mainNetwork": "Red principal", + "startMining": "⛏ Empezar a minar", + "stopMining": "⛏ Parar de minar", + "externalNode": "using external node", + "openRemix": "Open Remix IDE", + "nodeMode": "Chain download", + "fullNode": "Store full blockchain", + "lightNode": "Use light Node (experimental!)" + }, + "window": { + "label": "Ventana", + "minimize": "Minimizar", + "close": "Cerrar", + "toFront": "Traer Todo al Frente" + }, + "help": { + "label": "Ayuda", + "reportBug": "Report an issue on Github" + } + }, + "errors": { + "nodeConnect": "No se pudo conectar al nodo? Vea los registros para más información:", + "nodeStartup": "Parece que el nodo no se pudo iniciar, tiene uno ya funcionando? ¿Está actualizando la base de datos en este momento?", + "timeSync": { + "title": "El reloj de su ordenador no está sincronizado.", + "description": "Para sincronizar correctamente con la red Ethereum necesitas sincronizar el reloj de tu ordenador con un servidor de tiempo.", + "win32": "Ve a los ajustes del tiempo en las preferencias de sistema y marca la casilla. Vea esta guía para más detalles: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "Para permitir la sincronización con un servidor de tiempo instale \"ntp\" vía \"apt-get install ntp\".", + "darwin": "Para habilitar la sincronización del tiempo, abra las preferencias de tiempo y marque \"Ajuste la hora y la fecha automáticamente\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in downloaded node!", + "description": "__algorithm__: __hash__\n\nPlease install the __type__ node version __version__ manually." + }, + "legacyChain": { + "title": "Legacy chain detected", + "description": "Your node is currently on the unsupported Ethereum Classic chain. To use this chain use tools provided by the ethereum classic project at\nhttps://ethereumclassic.github.io.\n\nTo revert to the main ethereum chain follow the tutorial here:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Recargar", + "openDevTools": "Abrir las Herramientas de Desarrollador", + "inspectElements": "Inspeccionar Elemento" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ bloques restantes", + "blockReceived": "Nuevo bloque recibido", + "blockNumber": "Su último número de bloque", + "timeSinceBlock": "Tiempo transcurrido desde el último bloque", + "testnetExplain": "Estás en la red de pruebas, NO ENVÍE ningún ether real a estas direcciones", + "peers": "pares", + "checkingWhichNetwork": "Checking network...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "mainnetExplain": "You are on the main Ethereum global network", + "privatenetExplain": "You are on a private net, DO NOT SEND any real ether to these addresses", + "unknownnetExplain": "Unable to determine which network you are on" + }, + "sidebar": { + "buttons": { + "browser": "Navegar" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "No hay cuentas definidas", + "connect": "Connect" + } + }, + "startScreen": { + "runningNodeFound": "Encontrado nodo Ethereum funcionando!", + "startingNode": "Iniciando el nodo Ethereum...", + "startedNode": "Iniciando la aplicación...", + "nodeConnectionTimeout": "No se pudo iniciar un nodo Ethereum!
Si has instalado Geth, utiliza este comando para ejecutarlo:
geth --ipcpath __path__

O informa del problema ", + "nodeBinaryNotFound": "No se ha encontrado el binario del nodo Ethereum!
Por favor, inicie antes uno manualmente. ", + "nodeSyncing": "El nodo de Ethereum necesita sincronizarse, por favor espere...", + "nodeSyncInfo": "Descargando bloque __displayBlock__ de __highestBlock__.", + "nodeSyncConnecting": "Buscando pares...", + "peerSearchTimeout": "Omitir la búsqueda de pares", + "stoppingNode": "Stopping Ethereum node...", + "nodeStarting": "Ethereum node starting up...", + "nodeStarted": "Ethereum node started", + "nodeConnected": "Ethereum node connected", + "nodeStopping": "Ethereum node stopping...", + "nodeStopped": "Ethereum node stopped", + "nodeError": "Ethereum node connection error :'(", + "unableToBindPort": "Ethereum node cannot run. Is another instance already running?", + "nodeSyncInfoStates": "Downloading block __displayBlock__ of __highestBlock__,
Downloading chain structure __displayState__ of __displayKnownStates__", + "nodeSyncFoundPeers": "Connecting to __peers__ peers...", + "launchApp": "Launch Application", + "clientBinaries": { + "scanning": "Checking for node update...", + "downloading": "Downloading new node...", + "loadConfig": "Loading client config...", + "filtering": "Filtering client binaries...", + "done": "Ethereum node up-to-date...", + "error": "Error running downloaded binary." + } + }, + "popupWindows": { + "requestAccount": { + "title": "Crear cuenta", + "enterPassword": "Introduzca la contraseña", + "repeatPassword": "Repita la contraseña", + "creating": "Generando cuenta...", + "errors": { + "passwordMismatch": "Tus contraseñas no coinciden.", + "passwordTooShort": "Make a longer password" + } + }, + "unlockMasterPassword": { + "title": "Introduzca la contraseña maestra", + "enterPassword": "Introduzca la contraseña maestra", + "unlocking": "Desbloquenado...", + "errors": { + "wrongPassword": "La contraseña es incorrecta, inténtelo de nuevo." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Enviar transacción", + "contractExecution": "Ejecutar contrato", + "createContract": "Crear contrato" + }, + "contractExecutionInfo": "Estás a punto de ejecutar una función en un contrato. Esto puede implicar la transferencia de valor.", + "contractCreationInfo": "Vas a crear un contrato a partir de los datos proporcionados.", + "enterPassword": "Introduzca la contraseña para confirmar la transacción", + "unlocking": "Confirmando...", + "createContract": "Crear contrato", + "estimatedFee": "Tasa de comisión estimada", + "estimatedGasError": "Los datos no pueden ser ejecutados por lo que se utilizá todo el gas proporcionado.", + "gasPrice": "Precio del Gas", + "perMillionGas": "ether por millón de gas", + "gasLimit": "Proporcionar la tasa máxima", + "data": "Datos", + "buttons": { + "sendTransaction": "Enviar transacción" + }, + "errors": { + "connectionTimeout": "No se pudo conectar al nodo, ha dejado de funcionar en segundo plano?", + "wrongPassword": "Contraseña incorrecta", + "multipleKeysMatchAddress": "Multiple keys match address. Please remove duplicates from keystore (menu -> File -> Backup -> Accounts)", + "insufficientFundsForGas": "Insufficient funds in main account (etherbase) to pay for gas", + "sameAccount": "Can't send to itself" + }, + "transactionThrow": "The contract won't allow this transaction to be executed", + "noEstimate": "We couldn't estimate the gas.", + "parameters": "Parameters", + "showRawBytecode": "show raw data", + "showDecodedParameters": "show decoded parameters", + "lookupData": "Try to decode data", + "lookupDataExplainer": "Look this up on the internet", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount." + }, + "onboarding": { + "description": "Ethereum es una plataforma descentralizada para la construcción de aplicaciones en una blockchain: segura y a prueba de manipulaciones que puede transferir valor, propiedad y vive para siempre", + "goToTestnet": "Utiliza la red de pruebas (Rinkeby)", + "goToTestnetDescription": "Pruebe la tecnología libremente en una red de pruebas sin utilizar ether reales.", + "gotoMainnet": "Utilizar la red principal", + "gotoMainnetDescription": " Necesitarás algunos Ether para poder crear y ejecutar contratos. No se preocupe, nosotros le ayudaremos a obtener algunos...", + "doYouHaveAWalletFile": "¿Tiene un archivo de monedero?", + "walletFileDescription": "

Si participaste en la preventa de Ethereum en 2014, deberías tener un archivo llamado ethereum_wallet_backup.json. Se descargó después de la venta y también se envió a su correo electrónico.

", + "dropFilesHere": "Soltar el archivo de la pre-venta", + "creating": "Creando...", + "importing": "Importando...", + "skip": "Omitir este paso", + "next": "Siguiente", + "protectTitle": "Proteger su cuenta", + "protectDescription": "Elija una contraseña para su nueva cuenta que sea tan fuerte como si fuera a proteger las llaves de su casa!", + "accountTitle": "Cargarla!", + "accountTitleTestnet": "Minar algunos!", + "etherDescription": "La red ethereum está basada en un token llamado “Ether”. Necesitarás una pequeña cantidad de él para hacer cualquier cosa en la red Ethereum.", + "loadItDescription": "Si ya dispone de Bitcoin o cualquier otra criptomoneda, puede convertirlas fácilmente a ether utilizando changelly.

Recomendamos una cuantía de entre 0.25 a 1 ether.", + "mineItDescription": "En la red de pruebas puedes minar ether tú mismo desde el menú Desarrollar y eligiendo Empezar a minar.
NO INTENTE ENVIAR ETHER REALES A ESTA DIRECCIÓN ", + "you": "TÚ", + "etherbase": "Cuenta principal (etherbase)", + "depositBitcoin": "Depositar Bitcoin", + "learnIt": "Aprenda mientras espera", + "downloadingBlocks": "Descargando bloques", + "tutorial1Description": "

Ahora lo único que queda por hacer es esperar a que finalice la descarga. Aquí tiene unas sugerencias de lectura:

Haga su propio dinero

Haga una criptomoneda con una oferta de mercado fija, tokens que representen activos del mundo real, etc

", + "tutorial2Description": "

Crear una crowdsale

Recaude fondos para un objetivo común, totalmente confiable y sin terceros. Evite así el obstáculo de la financiación del sistema tradicional y vaya directamente a la fuente mediante la financiación de una organización a través de la blockchain.

", + "tutorial3Description": "

Organización en la Blockchain

Crea una organización autónoma con reglas inquebrantables sobre cómo el dinero puede ser gastado y quién puede tomar las decisiones. Deje que sus promotores tengan un papel activo en la forma en que se gasta el dinero

", + "buttons": { + "showPassword": "Mostrar contraseña", + "importAccount": "Importar cuenta", + "launchApp": "Lanzar Aplicación!", + "learnReceipt": "Aprender esta receta" + }, + "errors": { + "nodeNotStartedYet": "Espere unos segundos más hasta que su nodo esté completamente iniciado y vuelva a intentarlo", + "unknownFile": "Archivo no reconocido.", + "wrongPassword": "Contraseña incorrecta.", + "importFailed": "No se pudo importar el archivo por el error: __error__" + }, + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "syncMessage": "Block __displayBlock__ of __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ of __highestBlockString__ (Chain structure __statesPercent__%)", + "startingSync": "Getting ready to sync.." + }, + "connectAccount": { + "chooseAccountTitle": "Elegir sus cuentas", + "createAccount": "Crear nueva cuenta", + "pinToSidebar": "Mantener la aplicación en la barra lateral", + "connectAccountDescription": "Usted está compartiendo su identidad con __dappName__. Esto permite que la aplicación tenga acceso a la información pública de las cuentas seleccionadas, saldos incuindo relacionados con las mismas." + }, + "updateAvailable": { + "newVersionAvailable": "New __name__ version available", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Update and Restart", + "download": "Download new version", + "skipUpdate": "Skip Update", + "notNow": "Ask me later", + "checking": "Checking for updates to __name__...", + "noUpdateFound": "No update found. You are running the latest version of __name__." + } + } + }, + "elements": { + "checksumAlert": "Esta dirección parece válida, pero no tiene algunas de las características de seguridad que le protegerán contra los errores tipográficos así que compruebe que tenga la correcta. Si se proporciona, compruebe si el icono de seguridad coincide.", + "identiconHelper": "Este es un icono de seguridad. Si hay algún cambio en la dirección, el icono resultante debería ser completamente diferente", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.fa.i18n.json b/interface/i18n/mist.fa.i18n.json new file mode 100644 index 0000000..5a59a5a --- /dev/null +++ b/interface/i18n/mist.fa.i18n.json @@ -0,0 +1,281 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "About __app__", + "checkForUpdates": "Check for updates...", + "checkForNodeUpdates": "Check for Ethereum node updates...", + "services": "Services", + "hide": "Hide __app__", + "hideOthers": "Hide Others", + "showAll": "Show All", + "quit": "Quit __app__" + }, + "edit": { + "label": "Edit", + "undo": "Undo", + "redo": "Redo", + "cut": "Cut", + "copy": "Copy", + "paste": "Paste", + "selectAll": "Select all" + }, + "view": { + "label": "View", + "fullscreen": "Toggle Fullscreen", + "default": "Default" + }, + "file": { + "label": "Accounts", + "importPresale": "Import Accounts", + "newAccount": "New account", + "backup": "Backup", + "backupKeyStore": "Accounts", + "backupMist": "Application Data" + }, + "develop": { + "uploadToSwarm": "Upload to Swarm", + "label": "Develop", + "devTools": "Toggle Developer Tools", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Wallet UI", + "devToolsWebview": "__webview__", + "runTests": "Run tests", + "logFiles": "Show log file", + "externalNode": "using external node", + "ethereumNode": "Ethereum Node", + "network": "Network", + "mainNetwork": "Main Network", + "startMining": "⛏ Start Mining", + "stopMining": "⛏ Stop Mining", + "openRemix": "Open Remix IDE", + "nodeMode": "Chain download", + "fullNode": "Store full blockchain", + "lightNode": "Use light Node (experimental!)" + }, + "window": { + "label": "Window", + "minimize": "Minimize", + "close": "Close", + "toFront": "Bring All to Front" + }, + "help": { + "label": "Help", + "reportBug": "Report an issue on Github" + } + }, + "errors": { + "nodeConnect": "Couldn't connect to node? See the logs for more:", + "nodeStartup": "It seems like the node couldn't be started, do you already have one running? Is it upgrading the database right now?", + "timeSync": { + "title": "Your computer's clock is not synced.", + "description": "To successfully synchronize with the Ethereum network you need to sync your computer's clock with a time sync server.", + "win32": "Go to your Internet Time Settings in your system preferences and check the box. See this guide for details: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "To enable a time sync server install \"ntp\" via \"apt-get install ntp\".", + "darwin": "To enable time sync, open the time preferences and check \"Set the time and date automatically\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in downloaded node!", + "description": "__algorithm__: __hash__\n\nPlease install the __type__ node version __version__ manually." + }, + "legacyChain": { + "title": "Legacy chain detected", + "description": "Your node is currently on the unsupported Ethereum Classic chain. To use this chain use tools provided by the Ethereum Classic project at\nhttps://ethereumclassic.github.io.\n\nTo revert to the main ethereum chain follow the tutorial here:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Reload", + "openDevTools": "Open Developer Tools", + "inspectElements": "Inspect Element" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ blocks left", + "blockReceived": "New Block Received", + "blockNumber": "Your latest block number", + "timeSinceBlock": "Elapsed time since last block", + "checkingWhichNetwork": "Checking network...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "mainnetExplain": "You are on the main Ethereum global network", + "testnetExplain": "You are on the testnet, DO NOT SEND any real Ether to these addresses", + "privatenetExplain": "You are on a private net, DO NOT SEND any real Ether to these addresses", + "unknownnetExplain": "Unable to determine which network you are on", + "peers": "peers" + }, + "sidebar": { + "buttons": { + "browser": "Browse" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "No accounts set", + "connect": "Connect" + } + }, + "startScreen": { + "runningNodeFound": "Found running Ethereum node!", + "startingNode": "Starting Ethereum node...", + "stoppingNode": "Stopping Ethereum node...", + "startedNode": "Starting application...", + "nodeConnectionTimeout": "Couldn't start Ethereum node!
If you installed Geth, use this command to run it:
geth --ipcpath __path__

Or report an issue ", + "nodeBinaryNotFound": "No Ethereum node binary found!
Please start one manually before. ", + "nodeStarting": "Ethereum node starting up...", + "nodeStarted": "Ethereum node started", + "nodeConnected": "Ethereum node connected", + "nodeStopping": "Ethereum node stopping...", + "nodeStopped": "Ethereum node stopped", + "nodeError": "Ethereum node connection error :'(", + "unableToBindPort": "Ethereum node cannot run. Is another instance already running?", + "nodeSyncing": "Ethereum node needs to sync, please wait...", + "nodeSyncInfo": "Downloading block __displayBlock__ of __highestBlock__", + "nodeSyncInfoStates": "Downloading block __displayBlock__ of __highestBlock__,
Downloading chain structure __displayState__ of __displayKnownStates__", + "nodeSyncConnecting": "Looking for peers...", + "nodeSyncFoundPeers": "Connecting to __peers__ peers...", + "peerSearchTimeout": "Skip peer search", + "launchApp": "Launch Application", + "clientBinaries": { + "scanning": "Checking for node update...", + "downloading": "Downloading new node...", + "loadConfig": "Loading client config...", + "filtering": "Filtering client binaries...", + "done": "Ethereum node up-to-date...", + "error": "Error running downloaded binary." + } + }, + "popupWindows": { + "updateAvailable": { + "newVersionAvailable": "New __name__ version available", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Update and Restart", + "download": "Download new version", + "skipUpdate": "Skip Update", + "notNow": "Ask me later", + "checking": "Checking for updates to __name__...", + "noUpdateFound": "No update found. You are running the latest version of __name__." + }, + "requestAccount": { + "title": "Create account", + "enterPassword": "Enter password", + "repeatPassword": "Repeat password", + "creating": "Generating account...", + "errors": { + "passwordMismatch": "Your passwords don't match.", + "passwordTooShort": "Make a longer password" + } + }, + "unlockMasterPassword": { + "title": "Enter master password", + "enterPassword": "Enter master password", + "unlocking": "Unlocking...", + "errors": { + "wrongPassword": "Password is wrong, try again." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Send transaction", + "contractExecution": "Execute contract", + "createContract": "Create contract" + }, + "contractExecutionInfo": "You are about to execute a function on a contract. This might involve transfer of value.", + "contractCreationInfo": "You are about to create a contract from the provided data.", + "enterPassword": "Enter password to confirm the transaction", + "unlocking": "Confirming...", + "createContract": "Create contract", + "estimatedFee": "Estimated fee consumption", + "estimatedGasError": "It seems this transaction will fail. If you submit it, it may consume all the gas you send.", + "transactionThrow": "The contract won't allow this transaction to be executed", + "noEstimate": "We couldn't estimate the gas.", + "gasPrice": "Gas price", + "perMillionGas": "ether per million gas", + "gasLimit": "Provide maximum fee", + "data": "Raw Data", + "parameters": "Parameters", + "buttons": { + "sendTransaction": "Send transaction" + }, + "errors": { + "connectionTimeout": "Couldn't connect to the node, did it crash in the background?", + "wrongPassword": "Wrong password", + "multipleKeysMatchAddress": "Multiple keys match address. Please remove duplicates from keystore (menu -> File -> Backup -> Accounts)", + "insufficientFundsForGas": "Insufficient funds in main account (etherbase) to pay for gas", + "sameAccount": "Can't send to itself" + }, + "showRawBytecode": "show raw data", + "showDecodedParameters": "show decoded parameters", + "lookupData": "Try to decode data", + "lookupDataExplainer": "Look this up on the internet", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount." + }, + "onboarding": { + "description": "Ethereum is a public blockchain that features a turing complete programming for building solid, decentralized applications.", + "goToTestnet": "Use the test network (Rinkeby)", + "goToTestnetDescription": "Test the technology freely in a sandboxed testnet, without using real ether.", + "gotoMainnet": "Use the main network", + "gotoMainnetDescription": "You’ll need some Ether in order to create and execute contracts. Don't worry, we'll help you get some...", + "doYouHaveAWalletFile": "Do you have a wallet file?", + "walletFileDescription": "

If you participated on the Ethereum Pre-sale 2014, you should have a file named ethereum_wallet_backup.json. It was downloaded after the sale and also sent to your email

", + "dropFilesHere": "Drop pre-sale file", + "creating": "Creating...", + "importing": "Importing...", + "skip": "Skip this step", + "next": "Next", + "protectTitle": "Protect your account", + "protectDescription": "Choose a password for your new account. Make it as strong as if it would protect your house keys!", + "accountTitle": "Load it up!", + "accountTitleTestnet": "Mine some!", + "etherDescription": "The ethereum network is based on token called “Ether”. You’ll need a small amount of it to do anything on the Ethereum network.", + "loadItDescription": "If you already own Bitcoin, or any other cryptocurrency, you can easily convert it to ether using changelly.

We recommend loading somewhere between 0.25 to 1 ether.", + "mineItDescription": "On the testnet you can mine ether yourself by going to the Develop menu and choosing Start Mining.
DO NOT ATTEMPT TO SEND REAL ETHER TO THIS ADDRESS ", + "you": "YOU", + "etherbase": "Main account (etherbase)", + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "learnIt": "Learn while you wait", + "downloadingBlocks": "Downloading blocks", + "syncMessage": "Block __displayBlock__ of __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ of __highestBlockString__ (Chain structure __statesPercent__%)", + "tutorial1Description": "

Now the only thing left to do is wait for the download to finish. Here's some reading suggestions:

Make your own money

Make a cryptocurrency with a fixed market supply, tokens representing real world assets, etc

", + "tutorial2Description": "

Create a crowdsale

Raise funds for a common goal, fully trustable without a third party. Sidestep the hurdle of traditional funding system and go directly to the source by funding an organization via the blockchain.

", + "tutorial3Description": "

Create a blockchain organization

Create an autonomous organization with rules on spending money and making decisions for you and your investors.

", + "buttons": { + "showPassword": "Show password", + "importAccount": "Import account", + "launchApp": "Launch Application!", + "learnReceipt": "Learn this recipe" + }, + "errors": { + "nodeNotStartedYet": "Wait a few more seconds until your node is fully started and try again", + "unknownFile": "File not recognised.", + "wrongPassword": "Wrong password.", + "importFailed": "Couldn't import the file, got: __error__" + }, + "startingSync": "Getting ready to sync.." + }, + "connectAccount": { + "chooseAccountTitle": "Choose account", + "createAccount": "Create new account", + "pinToSidebar": "Pin app to the sidebar", + "connectAccountDescription": "You are sharing your identity with __dappName__. This allows the app to see any public information of your accounts, including balances connected to it." + } + } + }, + "elements": { + "checksumAlert": "This address looks valid, but it doesn't have some security features that will protect you against typos, so double check you have the right one. If provided, check if the security icon matches.", + "identiconHelper": "This is a security icon, if there's any change on the address the resulting icon should be a completely different one", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.fr.i18n.json b/interface/i18n/mist.fr.i18n.json new file mode 100644 index 0000000..b9306dc --- /dev/null +++ b/interface/i18n/mist.fr.i18n.json @@ -0,0 +1,282 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "À propos de __app__", + "checkForUpdates": "Chercher des mises à jour...", + "checkForNodeUpdates": "Check for Ethereum node updates...", + "services": "Services", + "hide": "Masquer __app__", + "hideOthers": "Masquer les autres", + "showAll": "Afficher tout", + "quit": "Quitter __app__" + }, + "edit": { + "label": "Modifier", + "undo": "Annuler", + "redo": "Rétablir", + "cut": "Couper", + "copy": "Copier", + "paste": "Coller", + "selectAll": "Tout sélectionner" + }, + "view": { + "label": "Voir", + "fullscreen": "Basculer en mode plein écran", + "default": "Default" + }, + "file": { + "label": "Fichier", + "importPresale": "Importer les comptes", + "newAccount": "Nouveau compte", + "backup": "Sauvegarder", + "backupKeyStore": "Comptes", + "backupMist": "Données de l'application" + }, + "develop": { + "uploadToSwarm": "Télécharger à Swarm", + "label": "Développement", + "devTools": "Outils de développement", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Wallet UI", + "devToolsWebview": "__webview__", + "runTests": "Lancer les tests", + "logFiles": "Afficher le journal de log", + "ethereumNode": "Nœud Ethereum", + "network": "Réseau", + "mainNetwork": "Réseau principal", + "startMining": "⛏ Commencer à miner", + "stopMining": "⛏ Arrêter de miner", + "externalNode": "using external node", + "openRemix": "Open Remix IDE", + "nodeMode": "Chain download", + "fullNode": "Store full blockchain", + "lightNode": "Use light Node (experimental!)" + }, + "window": { + "label": "Fenêtre", + "minimize": "Réduire", + "close": "Fermer", + "toFront": "Tout afficher au premier plan" + }, + "help": { + "label": "Aide", + "reportBug": "Report an issue on Github" + } + }, + "errors": { + "nodeConnect": "Vous n'arrivez pas à vous connecter à un nœud ? Regarder le journal de log pour en savoir plus :", + "nodeStartup": "Le nœud n'a apparemment pas pu être lancé, en avez-vous déjà un de lancé ? Est-il en train de mettre à jour la base de données actuellement ?", + "timeSync": { + "title": "L'horloge de votre ordinateur n'est pas synchronisée.", + "description": "Pour être correctement synchronisé avec le réseau Ethereum, vous devez synchronizer l'horloge de votre ordinateur avec un serveur de synchronisation de temps.", + "win32": "Allez dans vos paramètres d'heure Internet dans votre panneau de configuration et cochez la case. Lisez ce guide pour plus de détails : http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "Pour activer un serveur de synchronisation de temps, installez \"ntp\" via \"apt-get install ntp\".", + "darwin": "Pour activer la synchronisation du temps, ouvrez les préférences de temps et cochez \"Régler la date et l'heure automatiquement\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in downloaded node!", + "description": "__algorithm__: __hash__\n\nPlease install the __type__ node version __version__ manually." + }, + "legacyChain": { + "title": "Legacy chain detected", + "description": "Your node is currently on the unsupported Ethereum Classic chain. To use this chain use tools provided by the ethereum classic project at\nhttps://ethereumclassic.github.io.\n\nTo revert to the main ethereum chain follow the tutorial here:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Recharger", + "openDevTools": "Ouvrir les outils de développement", + "inspectElements": "Inspecter l'élément" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ blocs restant", + "blockReceived": "Nouveau bloc reçu", + "timeSinceBlock": "depuis le dernier bloc", + "peers": "pairs", + "blockNumber": "Your latest block number", + "checkingWhichNetwork": "Checking network...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "mainnetExplain": "You are on the main Ethereum global network", + "testnetExplain": "You are on the testnet, DO NOT SEND any real ether to these addresses", + "privatenetExplain": "You are on a private net, DO NOT SEND any real ether to these addresses", + "unknownnetExplain": "Unable to determine which network you are on" + }, + "sidebar": { + "buttons": { + "browser": "Parcourir" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "Aucun compte défini", + "connect": "Connect" + } + }, + "startScreen": { + "runningNodeFound": "Nœud Ethereum actif trouvé !", + "startingNode": "Démarrage du nœud Ethereum en cours...", + "startedNode": "Démarrage de l'application...", + "nodeConnectionTimeout": "Echec du démarrage du nœud Ethereum !
Si vous avez installé Geth, utilisez cette commande pour le lancer :
geth --ipcpath __path__

Ou signalez le problème ", + "nodeBinaryNotFound": "Pas de binaire du nœud Ethereum trouvé !
Veuillez en lancer d'abord un manuellement. ", + "nodeSyncing": "Le nœud Ethereum se synchronise, veuillez patienter...", + "nodeSyncInfo": "Télechargement du bloc __displayBlock__ depuis le bloc __highestBlock__.", + "nodeSyncConnecting": "À la recherche de pairs...", + "peerSearchTimeout": "Recherche de pairs ignorée", + "stoppingNode": "Stopping Ethereum node...", + "nodeStarting": "Ethereum node starting up...", + "nodeStarted": "Ethereum node started", + "nodeConnected": "Ethereum node connected", + "nodeStopping": "Ethereum node stopping...", + "nodeStopped": "Ethereum node stopped", + "nodeError": "Ethereum node connection error :'(", + "unableToBindPort": "Ethereum node cannot run. Is another instance already running?", + "nodeSyncInfoStates": "Downloading block __displayBlock__ of __highestBlock__,
Downloading chain structure __displayState__ of __displayKnownStates__", + "nodeSyncFoundPeers": "Connecting to __peers__ peers...", + "launchApp": "Launch Application", + "clientBinaries": { + "scanning": "Checking for node update...", + "downloading": "Downloading new node...", + "loadConfig": "Loading client config...", + "filtering": "Filtering client binaries...", + "done": "Ethereum node up-to-date...", + "error": "Error running downloaded binary." + } + }, + "popupWindows": { + "requestAccount": { + "title": "Créer un compte", + "enterPassword": "Entrer un mot de passe", + "repeatPassword": "Répéter le mot de passe", + "creating": "Génération du compte...", + "errors": { + "passwordMismatch": "Vos mots de passe ne correspondent pas.", + "passwordTooShort": "Make a longer password" + } + }, + "unlockMasterPassword": { + "title": "Entrer le mot de passe principal", + "enterPassword": "Entrer le mot de passe principal", + "unlocking": "Déverouillage...", + "errors": { + "wrongPassword": "Mauvais mot de passe, veuillez réessayer." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Envoyer la transaction", + "contractExecution": "Executer le contrat", + "createContract": "Créer un contrat" + }, + "contractExecutionInfo": "Vous êtes sur le point d'exécuter une fonction sur un contrat. Cela peut impliquer un transfert de valeur.", + "contractCreationInfo": "Vous êtes sur le point de créer un contrat à partir des données fournies.", + "enterPassword": "Entrez votre mot de passe pour confirmer la transaction", + "unlocking": "Confirmation...", + "createContract": "Créer contrat", + "estimatedFee": "Taxe de consommation estimée", + "estimatedGasError": "Les données n'ont pas pu être executées et vont donc utiliser tout le gaz fourni.", + "gasPrice": "Prix du gaz", + "perMillionGas": "ether par million de gaz", + "gasLimit": "Fournir la taxe maximum", + "data": "Données", + "buttons": { + "sendTransaction": "Envoyer la transaction" + }, + "errors": { + "connectionTimeout": "La connexion au nœud n'a pas pu s'établir, est-ce un plantage dans l'arrière-plan ?", + "wrongPassword": "Mauvais mot de passe", + "multipleKeysMatchAddress": "Multiple keys match address. Please remove duplicates from keystore (menu -> File -> Backup -> Accounts)", + "insufficientFundsForGas": "Insufficient funds in main account (etherbase) to pay for gas", + "sameAccount": "Can't send to itself" + }, + "transactionThrow": "The contract won't allow this transaction to be executed", + "noEstimate": "We couldn't estimate the gas.", + "parameters": "Parameters", + "showRawBytecode": "show raw data", + "showDecodedParameters": "show decoded parameters", + "lookupData": "Try to decode data", + "lookupDataExplainer": "Look this up on the internet", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount." + }, + "onboarding": { + "description": "Ethereum est une plateforme décentralisée pour la création d'applications sur une blockchain (chaîne de blocs) : logiciel inviolable qui peut transférer de la valeur et de la propriété et qui vit pour toujours", + "goToTestnet": "Utiliser le réseau Testnet (Rinkeby)", + "goToTestnetDescription": "Testez la technologie librement sur le réseau sandboxé (bac à sable), sans utiliser d'ether réel.", + "gotoMainnet": "Utiliser le réseau réel", + "gotoMainnetDescription": "Vous aurez besoin de quelques Ether afin de créer et exécuter des contrats. Ne vous en faites pas, nous allons vous aider à en obtenir...", + "doYouHaveAWalletFile": "Avez-vous un fichier wallet ?", + "walletFileDescription": "

Si vous avez participé à la prévente Ethereum 2014, vous devriez avoir un fichier nommé ethereum_wallet_backup.json. Il a été téléchargé après la vente et vous a aussi été envoyé par e-mail

", + "dropFilesHere": "Déposer un fichier de prévente ici", + "creating": "Création...", + "importing": "Importation...", + "skip": "Ignorer ces étapes", + "next": "Suivant", + "protectTitle": "Protéger votre compte", + "protectDescription": "Choisissez un mot de passe pour votre nouveau compte. Rendez-le aussi fort que s'il protégeait les clés de votre maison !", + "accountTitle": "Chargez le !", + "accountTitleTestnet": "Minez-en quelques-uns !", + "etherDescription": "Le réseau ethereum est basé sur un token (jeton) appelé “Ether”. Vous aurez besoin d'un petit montant de cela pour faire ce que vous souhaitez sur le réseau Ethereum.", + "loadItDescription": "Si vous possédez déjà des Bitcoin, ou n'importe quel autre crypto-monnaie, vous pouvez facilement les convertir en ether en utilisant changelly.

Nous recommandons d'en charger de 0.25 à 1 ether.", + "mineItDescription": "Sur le réseau Testnet vous pouvez miner de l'ether vous-même en allant sur le menu Développement et en choisissant Commencer à miner.
N'ESSAYEZ PAS D'ENVOYER DU VERITABLE ETHER A CETTE ADRESSE ", + "you": "VOUS", + "etherbase": "Compte principal (etherbase)", + "depositBitcoin": "Déposer des Bitcoin", + "learnIt": "Apprenez pendant que vous patientez", + "downloadingBlocks": "Téléchargement de blocs", + "tutorial1Description": "

Maintenant la seule chose qu'il reste à faire est d'attendre que le téléchargement se finisse. Voici quelques suggestions de lecture :

Faire son propre argent

Faire une crypto-monnaie avec une offre de marché fixe, les tokens représentant les actifs du monde réel, etc

", + "tutorial2Description": "

Créer un crowdsale

Lever des fonds pour un but commun, entièrement fiable et sans tiers. Éviter l'obstacle du système de financement traditionnel et aller directement à la source en finançant une organisation via la blockchain.

", + "tutorial3Description": "

Organisation de la blockchain

Créer une organisation autonome avec des règles inviolables sur la façon dont l'argent peut être dépensé et qui peut prendre des décisions. Laissez vos bailleurs de fonds prendre un rôle actif sur la façon dont l'argent est dépensé

", + "buttons": { + "showPassword": "Afficher le mot de passe", + "importAccount": "Importer un compte", + "launchApp": "Lancer l'application !", + "learnReceipt": "Apprendre cette recette" + }, + "errors": { + "nodeNotStartedYet": "Attendez quelques secondes de plus avant que votre nœud soit initialisé et essayez de nouveau", + "unknownFile": "Fichier non reconnu.", + "wrongPassword": "Mauvais mot de passe.", + "importFailed": "Echec à l'importation du fichier avec l'erreur : __error__" + }, + "buyEther": "Acheter Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "syncMessage": "Block __displayBlock__ of __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ of __highestBlockString__ (Chain structure __statesPercent__%)", + "startingSync": "Getting ready to sync.." + }, + "updateAvailable": { + "newVersionAvailable": "New __name__ version available", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Update and Restart", + "download": "Download new version", + "skipUpdate": "Skip Update", + "notNow": "Ask me later", + "checking": "Checking for updates to __name__...", + "noUpdateFound": "No update found. You are running the latest version of __name__." + }, + "connectAccount": { + "chooseAccountTitle": "Choose account", + "createAccount": "Create new account", + "pinToSidebar": "Pin app to the sidebar", + "connectAccountDescription": "You are sharing your identity with __dappName__. This allows the app to see any public information of your accounts, including balances connected to it." + } + } + }, + "elements": { + "checksumAlert": "Cette adresse semble valide, mais elle n'a pas de fonctionnalités de sécurité qui vous protégeront contre les fautes de frappe, alors revérifiez que vous avez la bonne. Si elle est fournie, vérifiez si l'icône de sécurité correspond.", + "identiconHelper": "C'est une icone de sécurité, si il y a le moindre changement sur l'adresse l'icône résultante devrait être complètement différente", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.it.i18n.json b/interface/i18n/mist.it.i18n.json new file mode 100644 index 0000000..f901729 --- /dev/null +++ b/interface/i18n/mist.it.i18n.json @@ -0,0 +1,272 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "Info su __app__", + "checkForUpdates": "Controlla aggiornamenti...", + "checkForNodeUpdates": "Controlla aggiornamento dei nodi Ethereum...", + "services": "Servizi", + "hide": "Nascondi __app__", + "hideOthers": "Nascondi il resto", + "showAll": "Mostra tutto", + "quit": "Esci da __app__" + }, + "edit": { + "label": "Modifica", + "undo": "Annulla", + "redo": "Ripristina", + "cut": "Taglia", + "copy": "Copia", + "paste": "Incolla", + "selectAll": "Seleziona tutto" + }, + "view": { + "label": "Visualizza", + "fullscreen": "Schermo intero", + "default": "Default" + }, + "file": { + "label": "File", + "importPresale": "Importa Accounts", + "newAccount": "Nuovo account", + "backup": "Backup", + "backupKeyStore": "Accounts", + "backupMist": "Dati applicativi" + }, + "develop": { + "uploadToSwarm": "Carica a Swarm", + "label": "Sviluppo", + "devTools": "Strumenti di sviluppo", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Portafoglio UI", + "devToolsWebview": "__webview__", + "runTests": "Esegui Test", + "logFiles": "Mostra file di log", + "ethereumNode": "Nodo Ethereum", + "network": "Rete", + "mainNetwork": "Rete principale", + "startMining": "⛏ Inizia mining", + "stopMining": "⛏ Ferma mining", + "openRemix": "Apri IDE Remix" + }, + "window": { + "label": "Finestra", + "minimize": "Minimizza", + "close": "Chiudi", + "toFront": "Tutte in primo piano" + }, + "help": { + "label": "Aiuto", + "reportBug": "Riporta un problema su Github" + } + }, + "errors": { + "nodeConnect": "Impossibile connettersi al nodo. Controlla i log per dettagli:", + "nodeStartup": "Il nodo non puó essere avviato, ne hai giá uno in esecuzione? Il database è in fase di aggiornamento in questo momento?", + "timeSync": { + "title": "Il tuo orologio di sistema non è sincronizzato.", + "description": "E' necessario sincronizzare l'orologio di sistema con un time server per connettere correttamente il tuo nodo alla rete Ethereum.", + "win32": "Apri le impostazioni dell'orologio di sistema, seleziona Orario internet e metti un tick sul box. Segui questa guida (in inglese) per i dettagli: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "Per abilitare la sincronia con un time server installa \"ntp\" via \"apt-get install ntp\".", + "darwin": "Per abilitare la sincronia dell'ora, apri le preferenze di orario e spunta \"Setta ora e data automaticamente\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum non corrispondente nel nodo scaricato!", + "description": "__algorithm__: __hash__\n\nPer favore installa la __type__ versione nodo __version__ manualmente." + }, + "legacyChain": { + "title": "Rilevata chain obsoleta", + "description": "Il tuo nodo si trova su una chain Ethereum Classic non supportata. Per usare questa chain usa strumenti forniti dal progetto ethereum classic da \nhttps://ethereumclassic.github.io.\n\nPer ritornare sulla chain principale di ethereum segui il tutorial seguente:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Ricarica", + "openDevTools": "Apri strumenti di sviluppo", + "inspectElements": "Ispeziona elemento" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ blocchi mancanti", + "blockReceived": "Nuovo blocco ricevuto", + "blockNumber": "Il tuo ultimo numero di blocco", + "timeSinceBlock": "Tempo trascorso dall'ultimo blocco", + "testnetExplain": "Sei connesso alla testnet, NON INVIARE alcun ether reale a questi indirizzi", + "peers": "nodi", + "checkingWhichNetwork": "Controllo rete...", + "privateNetwork": "Private-net" + }, + "sidebar": { + "buttons": { + "browser": "Sfoglia" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "Nessun account impostato", + "connect": "Connetti" + } + }, + "startScreen": { + "runningNodeFound": "Trovato nodo Ethereum in esecuzione!", + "startingNode": "Avvio nodo Ethereum ...", + "startedNode": "Avvio applicazione...", + "nodeConnectionTimeout": "Impossibile avviare un nodo Ethereum!
Se hai installato Geth, usa questo comando per eseguirlo:
geth --ipcpath __path__

o riporta il problema ", + "nodeBinaryNotFound": "Impossibile trovare l'eseguibile del nodo Ethereum !
Per favore avvialo manualmente prima. ", + "nodeSyncing": "Il nodo Ethereum deve sincronizzarsi, attendere prego...", + "nodeSyncInfo": "Scaricamento blocco __displayBlock__ di __highestBlock__.", + "nodeSyncConnecting": "Alla ricerca di nodi...", + "nodeStarting": "Nodo Ethereum in avvio...", + "nodeStarted": "Nodo Ethereum avviato", + "nodeConnected": "Nodo Ethereum connesso", + "nodeStopping": "Nodo Ethereum in arresto...", + "nodeStopped": "Nodo Ethereum arrestato", + "nodeError": "Nodo Ethereum errore di connessione :'(", + "unableToBindPort": "Nodo Ethereum non in esecuzione. Esiste altra istanza in esecuzione?", + "nodeSyncInfoStates": "Scaricamento blocco __displayBlock__ of __highestBlock__,
Scaricamento struttura chain __displayState__ of __displayKnownStates__", + "nodeSyncFoundPeers": "Connessione a __peers__ peers...", + "launchApp": "Avvia Applicazione", + "clientBinaries": { + "scanning": "Controlla aggiornamento nodo...", + "downloading": "Scaricamento nuovo nodo...", + "loadConfig": "Caricamento configurazione client...", + "filtering": "Filtro codice binario del client...", + "done": "Nodo Ethereum aggiornato...", + "error": "Errore durante lo scaricamento del codice binario." + } + }, + "popupWindows": { + "requestAccount": { + "title": "Crea account", + "enterPassword": "Immetti password", + "repeatPassword": "Ripeti password", + "creating": "Generazione account...", + "errors": { + "passwordMismatch": "Le due password non sono uguali.", + "passwordTooShort": "Usa una password più lunga" + } + }, + "unlockMasterPassword": { + "title": "Inserisci password master", + "enterPassword": "Inserisci password master", + "unlocking": "Sblocco in corso...", + "errors": { + "wrongPassword": "Password errata, riprova." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Invia transazione", + "contractExecution": "Esegui contratto", + "createContract": "Crea contratto" + }, + "contractExecutionInfo": "Stai per eseguire una funzione su di un contratto. Questo potrebbe comportare trasferimento di valuta.", + "contractCreationInfo": "Stai per creare un contratto con i dati forniti.", + "enterPassword": "Inserisci la password per confermare la transazione", + "unlocking": "Conferma in corso...", + "createContract": "Creazione contratto", + "estimatedFee": "Stima consumo (commissione)", + "estimatedGasError": "Dati non eseguibili, quindi verrà utilizzato tutto il gas fornito.", + "gasPrice": "Prezzo carburante (Gas)", + "perMillionGas": "ether per milioni di gas", + "gasLimit": "Imposta limite di gas", + "data": "Dati", + "buttons": { + "sendTransaction": "Invia transazione" + }, + "errors": { + "connectionTimeout": "Impossibile connettersi al nodo, è forse terminato in modo inaspettato ?", + "wrongPassword": "Password errata", + "multipleKeysMatchAddress": "Chiavi multiple per lo stesso indirizzo, per favore eliminare i duplicati dal keystore (menu -> accounts -> backup -> accounts)", + "insufficientFundsForGas": "Credito insufficiente nel account pricipale (etherbase) per pagare il gas", + "sameAccount": "Non può inviare a se stesso" + }, + "transactionThrow": "Il contratto non consente l'esecuzione di questa transazione", + "noEstimate": "Impossibile stimare il gas necessario.", + "parameters": "Parametri", + "showRawBytecode": "mostra dati grezzi", + "showDecodedParameters": "mostra parameteri decodificati", + "lookupData": "Provo a decodificare i dati", + "lookupDataExplainer": "Cerca questo su internet", + "overBlockGasLimit": "Il gas richiesto per questa esecuzione potrebbe eccedere il gas limit del blocco.", + "notEnoughGas": "Il Gas potrebbe non essere sufficiente per completare con successo questa transazione.
Clicca qui per aumentare la quantità di gas." + }, + "onboarding": { + "description": "Ethereum é una piattaforma decentralizzata per costruire applicazioni sfruttando una blockchain: software a prova di manomissione che puó trasferire valore e proprietá vivendo per sempre", + "goToTestnet": "Usa la rete di test (Rinkeby)", + "goToTestnetDescription": "Prova la tecnologia liberamente utilizzando una testnet, senza l'utilizzo di vero ether.", + "gotoMainnet": "Usa la rete principale", + "gotoMainnetDescription": " Avrai bisogno di un po di Ether per creare ed eseguire contratti. Non ti preoccupare, ti aiuteremo ad ottenerne un pó...", + "doYouHaveAWalletFile": "Hai un file per il wallet ?", + "walletFileDescription": "

Se hai partecipato alla pre-vendita Ethereum nel 2014, dovresti avere un file nominatoethereum_wallet_backup.json. E' stato scaricato dopo la vendita e inoltre inviato al tuo indirizzo e-mail

", + "dropFilesHere": "Trascina file pre-vendita", + "creating": "Creazione...", + "importing": "Importazione...", + "skip": "Salta il passaggio", + "next": "Successivo", + "protectTitle": "Proteggi il tuo account", + "protectDescription": "Scegli una password per il tuo nuovo account. Rendila piu complicata possibile come se dovesse proteggere le tue chiavi di casa!", + "accountTitle": "Stra-caricalo!", + "accountTitleTestnet": "Mina un pó!", + "etherDescription": "La rete ethereum é basata su di un token chiamato “Ether”. Avrai bisogno di una piccola quantitá di ether per fare qualsiasi cosa sulla rete Ethereum.", + "loadItDescription": "Se possiedi giá Bitcoin, o qualunque altra cryptovaluta, puoi facilmente convertirla in eth usando changelly.

Raccomandiamo di depositare da 0.25 a 1 ether.", + "mineItDescription": "Sulla rete di test (testnet) puoi minare ether in autonomia utilizzando il menu' Sviluppo e selezionando Inizia Mining.
NON TENTARE DI INVIARE ETHER REALE A QUESTO INDIRIZZO", + "you": "TU", + "etherbase": "Account principale (etherbase)", + "depositBitcoin": "Deposita Bitcoin", + "learnIt": "Impara mentre aspetti", + "downloadingBlocks": "Scaricamento blocchi ", + "tutorial1Description": "

Ora l'ultima cosa rimasta e' aspettare che il download sia completato. Eccoti alcuni consigli di letture:

Conia la tua moneta

Conia una cryptovaluta con una offerta di mercato fissa, tokens che rappresentano beni nel mondo reale, etc

", + "tutorial2Description": "

Crea una crowdsale

Raccogli fondi per uno scopo comune, in piena fiducia e senza terze parti. Evita le difficoltá di un sistema tradizionale di raccolta fondi e raggiungi direttamente la fonte finanziando una organizzazione tramite la blockchain.

", + "tutorial3Description": "

Organizzazione su Blockchain

Crea una organizzazione autonoma con regole indissolubili riguardo a come i soldi possono essere spesi e da chi puó prendere le decisioni. Permetti ai tuoi sostenitori di partecipare attivamente riguardo a come i soldi vengono spesi

", + "buttons": { + "showPassword": "Mostra password", + "importAccount": "Importa account", + "launchApp": "Avvia Applicazione!", + "learnReceipt": "Dettagli ricevuta" + }, + "errors": { + "nodeNotStartedYet": "Attendi qualche secondo ancora finché il tuo nodo non é completamente avviato e riprova", + "unknownFile": "File non riconosciuto.", + "wrongPassword": "Password errata.", + "importFailed": "Impossibile importare il file: __error__" + }, + + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "syncMessage": "Block __displayBlock__ of __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ of __highestBlockString__ (Chain structure __statesPercent__%)", + "startingSync": "Getting ready to sync.." + }, + "updateAvailable": { + "newVersionAvailable": "Nuova __name__ versione disponibile", + "version": "Versione", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Aggiorna e Riavvia", + "download": "Scarica nuova versione", + "skipUpdate": "Salta Aggiornamento", + "checking": "Controlla aggiornamenti a __name__...", + "noUpdateFound": "Nessuna aggiornamento trovato. Stai eseguendo l'ultima versione di __name__." + + }, + "connectAccount": { + "chooseAccountTitle": "Scegli account", + "createAccount": "Crea nuovo account", + "pinToSidebar": "Aggancia applicazione alla barra laterale", + "connectAccountDescription": "Sta per condividere la tua identità con __dappName__. Questo consente all'applicazione di vedere ogni informazione pubblica del tuo account, compreso il relativo balance associato." + } + } + }, + "elements": { + "checksumAlert": "Questo indirizzo sembra valido ma non ha alcuna sicurezza aggiuntiva che ti possa proteggere da errori di battitura, ricontrolla quindi che sia quello corretto. Se disponibile, verifica che le icone di sicurezza siano uguali.", + "identiconHelper": "Questa è un icona di sicurezza, se c'è qualsiasi cambiamento nell'indirizzo l'icona risultante sarà completamente differente", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.ja.i18n.json b/interface/i18n/mist.ja.i18n.json new file mode 100644 index 0000000..e3792ea --- /dev/null +++ b/interface/i18n/mist.ja.i18n.json @@ -0,0 +1,283 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "__app__ について", + "checkForUpdates": "アップデートの確認...", + "checkForNodeUpdates": "EtherCore ノードのアップデートの確認...", + "services": "サービス", + "hide": "__app__ を隠す", + "hideOthers": "ほかを隠す", + "showAll": "すべてを表示", + "quit": " __app__ を終了する" + }, + "edit": { + "label": "編集", + "undo": "元に戻す", + "redo": "やり直す", + "cut": "カット", + "copy": "コピー", + "paste": "ペースト", + "selectAll": "全てを選択" + }, + "view": { + "label": "ビュー", + "fullscreen": "フルスクリーン", + "default": "デフォルト" + }, + "file": { + "label": "アカウント", + "importPresale": "アカウントを読み込む", + "newAccount": "新規アカウント", + "backup": "バックアップを取る", + "backupKeyStore": "アカウント", + "backupMist": "アプリケーションデータ" + }, + "develop": { + "uploadToSwarm": "Swarm にアップロード", + "label": "開発", + "devTools": "開発者用ツール", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Wallet UI", + "devToolsWebview": "__webview__", + "runTests": "テストを実行する", + "logFiles": "ログファイルを表示する", + "ethereumNode": "EtherCore ノード", + "network": "ネットワーク", + "mainNetwork": "メインネットワーク", + "startMining": "⛏ マイニングを始める", + "stopMining": "⛏ マイニングを中止する", + "externalNode": "外部のノードを使用する", + "openRemix": "Remix IDE を開く", + "nodeMode": "チェーンダウンロード", + "fullNode": "フルノードを保存する", + "lightNode": "ライトノードを使う (実験的なものです!)" + }, + "window": { + "label": "ウィンドウ", + "minimize": "最小化", + "close": "閉じる", + "toFront": "前面に表示" + }, + "help": { + "label": "ヘルプ", + "reportBug": "バグレポート" + } + }, + "errors": { + "nodeConnect": "ノードにつながりませんか? ログを見て下さい。", + "nodeStartup": "ノードが始まらないようです。既に動かしていますか?今すぐデータベースを動かしますか?", + "timeSync": { + "title": "コンピューターのクロックが未だ同期されていません.", + "description": "EtherCore のネットワークと同期を成功させるためには、時間を同期させるサーバーとあなたのコンピューターを同期させる必要があります。", + "win32": "システム設定を開き、「インターネットの時間設定」を開いてチェックボックスにチェックを入れて下さい。詳しくはこちらのガイドをご覧下さい: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "時間を同期させるサーバーを使うためには、 \"ntp\" を \"apt-get install ntp\" をコマンドラインから入力してインストールする必要があります。", + "darwin": "時間を同期するためには、時間設定を開き \"時間と日付を自動で同期\" にチェックすることが必要です." + }, + "nodeChecksumMismatch": { + "title": "ダウンロードしたノードのチェックサムの照合に失敗しました!", + "description": "__algorithm__: __hash__\n\nノード __type__ バージョン __version__ を手動でインストールしてください." + }, + "legacyChain": { + "title": "レガシーチェーンを検出しました", + "description": "あなたのノードは現在サポートされていません. Ethereum のクラシックプロジェクトによって提供されるこのチェーン使用ツールを使用するには \nhttps://ethereumclassic.github.io.\n\nメイン Ethereum チェーンに戻す方法のチュートリアルはこちら:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "リロード", + "openDevTools": "開発者用ツールを開く", + "inspectElements": "要素を検証する" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ ブロックが残っています", + "blockReceived": "新しいブロックを受け取りました", + "timeSinceBlock": "最後のブロックから", + "peers": "ピアー", + "blockNumber": "ブロック番号", + "checkingWhichNetwork": "ネットワークをチェックしています...", + "mainNetwork": "メインネット", + "testNetwork": "テストネット", + "privateNetwork": "プライベートネット", + "mainnetExplain": "ここは EtherCore のメインネットです", + "testnetExplain": "ここはテストネットです。絶対に本物の ehter を送らないでください", + "privatenetExplain": "ここはプライベートっとです。絶対に本物の ether を送らないでください", + "unknownnetExplain": "どこのネットワークにいるか判定できませんでした" + }, + "sidebar": { + "buttons": { + "browser": "探す" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "アカウントがセットされていません", + "connect": "接続" + } + }, + "startScreen": { + "runningNodeFound": "起動している EtherCore ノードを見つけました!", + "startingNode": "EtherCore ノードを開始しています。", + "startedNode": "EtherCore ノードは開始されました...", + "nodeConnectionTimeout": "EtherCore ノードをスタート出来ませんでした!
もしGethをインストールしているならば,このコマンドを使ってみてください:
geth --ipcpath __path__

もしくは問題を報告して下さい。 ", + "nodeBinaryNotFound": "EtherCore ノードバイナリーが見つかりませんでした。
手動でスタートして下さい。 ", + "nodeSyncing": "EtherCore ノードは同期中です...", + "nodeSyncInfo": "ブロックをダウンロードしています。 __displayBlock__ / __highestBlock__.", + "nodeSyncConnecting": "ピアーを探しています。...", + "peerSearchTimeout": "ピアーの検索を中止しています", + "stoppingNode": "ノードを終了しています...", + "nodeStarting": "ノードを起動しています...", + "nodeStarted": "ノードは起動されました", + "nodeConnected": "ノードは接続されました", + "nodeStopping": "ノードを終了しています...", + "nodeStopped": "ノードは終了しました", + "nodeError": "ノード接続エラー :'(", + "unableToBindPort": "EtherCore ノードが実行できません。既に他のインスタンスが立ち上がっていませんか?", + "nodeSyncInfoStates": "ブロック __displayBlock__ / __highestBlock__ ダウンロード中,
チェーン構造 __displayState__ / __displayKnownStates__ ダウンロード中", + "nodeSyncFoundPeers": "ピアー __peers__ に接続中...", + "launchApp": "アプリケーションを起動", + "clientBinaries": { + "scanning": "ノードのアップデートを確認中...", + "downloading": "新たなノードをダウンロード中...", + "loadConfig": "クライアントの設定を読み込み中...", + "filtering": "クライアントのバイナリをフィルタリング中...", + "done": "EtherCore ノードは最新です", + "error": "ダウンロードしたバイナリでエラーが発生." + } + }, + "popupWindows": { + "requestAccount": { + "title": "アカウントを作成する", + "enterPassword": "パスワードを入力する", + "repeatPassword": "パスワードを繰り返し入力する", + "creating": "アカウントを生成しています...", + "errors": { + "passwordMismatch": "パスワードが正しくありません", + "passwordTooShort": "もっと長いパスワードにしてください" + } + }, + "unlockMasterPassword": { + "title": "マスターパスワードを入力する", + "enterPassword": "マスターパスワードを入力する", + "unlocking": "ロックを解除しています...", + "errors": { + "wrongPassword": "パスワードが間違っています。再度トライして下さい" + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "トランザクションを送信する", + "contractExecution": "コントラクトを実行する", + "createContract": "コントラクトを作成する" + }, + "contractExecutionInfo": "コントラクトの関数を実行しようとしています。これはバリューの移転を含むことがあります。", + "contractCreationInfo": "与えられたデータからコントラクトを作成しようとしています。", + "enterPassword": "トランザクションを実行するためにパスワードを入力して下さい。", + "unlocking": "承認しています...", + "createContract": "コントラクトを作成する", + "estimatedFee": "推定されるトランザクションフィーの消費", + "estimatedGasError": "データが実行できませんでした、そのため全ての GAS が消費されます。", + "gasPrice": "GAS 価格", + "perMillionGas": "100 万 GAS ごとの Ether", + "gasLimit": "GAS リミット", + "data": "データ", + "buttons": { + "sendTransaction": "トランザクションを送信" + }, + "errors": { + "connectionTimeout": "ノードにつなげませんでした、バックグラウンドで落ちていますか?", + "wrongPassword": "パスワードが間違っています", + "multipleKeysMatchAddress": "複数のキーが一致する場合は、キーストアから重複を削除してください (アカウント -> バックアップを取る -> アカウント)", + "insufficientFundsForGas": "GAS を支払うためにメインアカウント(etherbase)に不十分な資金", + "sameAccount": "同一アカウントには送信できません" + }, + "transactionThrow": "契約により、この取引は実行されません", + "noEstimate": "GAS を見積もることができませんでした", + "parameters": "パラメータ", + "showRawBytecode": "生データを見る", + "showDecodedParameters": "デコードされたパラメータを見る", + "lookupData": "データをデコードする", + "lookupDataExplainer": "インターネットでこれを確認してください", + "overBlockGasLimit": "この実行に必要な GAS は、ブロック GAS の限界を超える可能性があります", + "notEnoughGas": "GAS が不足してトランザクションが正常に終了できませんでした.
ここをクリックして GAS を増やしてください." + }, + "onboarding": { + "description": "EtherCore は分散型のプラットフォームで、ブロックチェーン上でアプリケーションを作成することが出来ます。価値を転送することが出来、永続的に稼働するセキュリティの高いソフトウェアを作ることが出来ます。", + "goToTestnet": "テストネットワークを使用する (Rinkeby)", + "goToTestnetDescription": "本物の Ether を使わず、サンドボックスのテストネットで、テクノロジーを自由に使う。", + "gotoMainnet": "メインネットワークを使用する", + "gotoMainnetDescription": "コントラクトを作成して実行するためにいくらかの Ether が必要となるでしょう。心配することはありません、手に入れるためにこちらの方法があります。...", + "doYouHaveAWalletFile": "ウォレットファイルを持っていますか?", + "walletFileDescription": "

もし2014年のプリセールに参加していたら、 ethereum_wallet_backup.jsonという名前のファイルを持っているはずです。プリセールのあとにダウンロードしているか、もしくは Email にて受け取っているはずです。

", + "dropFilesHere": "プリセールファイルを削除する", + "creating": "作成しています...", + "importing": "インポート中です...", + "skip": "このステップをスキップする", + "next": "次へ", + "protectTitle": "アカウントを守る", + "protectDescription": "新しいアカウントのためにパスワードを作成する. 必ず強いパスワードにしてください!", + "accountTitle": "もっとダウンロードする!", + "accountTitleTestnet": "マイニングを行う!", + "etherDescription": "EtherCore ネットワークは“Ether と呼ばれるトークンに基づき成り立っています. EtherCoreネットワークで何かを行うためには必ず必要となります。", + "loadItDescription": "既にもし Bitcoin を持っているか, もしくは他の暗号通貨を持っている場合には簡単に changelly で変換する事ができます。

私たちは 0.25 から 1 ether の間で変換することをおすすめします.", + "mineItDescription": "テストネットでは自分自身でマイニングを行うか、 Develop メニューから マイニングを始めるを選んでください.
絶対にこのアドレスには Ether を送らないでください ", + "you": "あなた", + "etherbase": "メインアカウント(etherbase)", + "depositBitcoin": "Bitcoin をデポジットする", + "learnIt": "待っている間に EthereumWallet のことを学ぶ", + "downloadingBlocks": "ブロックをダウンロードする", + "tutorial1Description": "

全て終わり、後はダウンロードが終了するのは待つだけです。いくつか次の提案があります。:

あなたのお金を発行する

暗号通貨を一定の供給と共に作成することが出来、トークンを現実世界のアセットと関連付ける事ができます。

", + "tutorial2Description": "

クラウドセールを作成する

第三者の介入無く共通のゴールを目指して一緒に進みましょう. 従来のファンディングシステムではとは異なり、ブロックチェーンを用いてダイレクトに資金を集める事ができます。

", + "tutorial3Description": "

ブロックチェーン組織

どのようにして資金を使うのか、そして誰が決定するのかについて破ることが出来ないルールを持った自律的な組織を作成しましょう。そして、あなたの支援者に、どのように資金が使われるのかをアクティブに考え、行動してもらうことが出来ます。

", + "buttons": { + "showPassword": "パスワードを見せる", + "importAccount": "アカウントをインポートする", + "launchApp": "アプリケーションをスタート!", + "learnReceipt": "このレシピを学ぶ" + }, + "errors": { + "nodeNotStartedYet": "ノードが起動するまでもう少し待ってください", + "unknownFile": "ファイルを認識できませんでした.", + "wrongPassword": "パスワードが間違っています", + "importFailed": "ファイルが読み込めませんでした: __error__のエラーです" + }, + + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "syncMessage": "ブロック __displayBlock__ / __highestBlockString__", + "syncMessageWithStates": "ブロック __displayBlock__ / __highestBlockString__ (チェーン構造 __statesPercent__%)", + "startingSync": "動機を開始しています..." + }, + "updateAvailable": { + "newVersionAvailable": "新しバージョン __name__ が利用可能です", + "version": "バージョン", + "downloadURL": "ダウンロード URL", + "checksum": "チェックサム", + "downloadAndRestart": "アップデートして再起動", + "download": "新しいバージョンをダウンロード", + "skipUpdate": "アップデートをスキップ", + "notNow": "今はしない", + "checking": "__name__ のバージョンにアップデートがないか確認しています...", + "noUpdateFound": "新しいバージョンは見つかりませんでした. あなたの __name__ は最新バージョンです." + }, + "connectAccount": { + "chooseAccountTitle": "アカウントを選ぶ", + "createAccount": "アカウントを新規作成", + "pinToSidebar": "サイドバーにピンする", + "connectAccountDescription": "__dappName__ であなたの身元を共有しています。これにより、アプリはアカウントに接続された残高を含むアカウントの公開情報をすべて表示することができます。" + } + } + }, + "elements": { + "checksumAlert": "このアドレスは正しく見えますが、誤字があります。もう一度確認して再度入力下さい。", + "identiconHelper": "これはセキュリティアイコンです。もし何かアドレスに変更があればアイコンは全く異なるものになります。", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.ko.i18n.json b/interface/i18n/mist.ko.i18n.json new file mode 100644 index 0000000..64a89a9 --- /dev/null +++ b/interface/i18n/mist.ko.i18n.json @@ -0,0 +1,253 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "__app__에 대하여", + "checkForUpdates": "업데이트 확인...", + "checkForNodeUpdates": "EtherCore 노드 업데이트 확인...", + "services": "서비스", + "hide": "__app__ 숨기기", + "hideOthers": "다른 창 숨기기", + "showAll": "모두 보기", + "quit": "__app__ 종료" + }, + "edit": { + "label": "수정", + "undo": "되돌리기", + "redo": "재적용", + "cut": "오려두기", + "copy": "복사하기", + "paste": "붙이기", + "selectAll": "모두 선택" + }, + "view": { + "label": "보기", + "fullscreen": "전체화면으로", + "default": "기본" + }, + "file": { + "label": "계정", + "importPresale": "계정 추가하기", + "newAccount": "새 계정", + "backup": "백업", + "backupKeyStore": "계정키 백업", + "backupMist": "어플리케이션 데이터", + "swarmUpload": "Swarm에 업로드" + }, + "develop": { + "label": "개발", + "devTools": "개발도구 전환", + "devToolsMistUI": "미스트 UI", + "devToolsWalletUI": "지갑 UI", + "devToolsWebview": "__webview__", + "runTests": "테스트 실행", + "logFiles": "로그파일 보기", + "ethereumNode": "EtherCore 노드", + "network": "네트워크", + "mainNetwork": "메인 네트워크", + "startMining": "⛏ 채굴 시작(테스트넷만 해당)", + "stopMining": "⛏ 채굴 중단", + "openRemix": "Remix IDE 열기" + }, + "window": { + "label": "창", + "minimize": "최소화", + "close": "닫기", + "toFront": "전면으로 보내기" + }, + "help": { + "label": "도움말", + "discord": "디스코드", + "reddit": "레딧", + "reportBug": "깃허브에 이슈 보고" + } + }, + "errors": { + "nodeConnect": "노드에 연결할 수 없습니다? 자세한 것은 로그를 확인하세요:", + "nodeStartup": "노드가 시작하지 못하고 있습니다. 이미 다른 노드를 실행하고 있거나 현재 데이터베이스를 업그레이드 하고 있나요?", + "timeSync": { + "title": "당신의 컴퓨터 시간이 동기화되어 있지 않습니다.", + "description": "EtherCore 네트워크와 성공적으로 동기화하기 위해서는 사용하시는 컴퓨터의 시간을 시간서버와 동기화해야 합니다.", + "win32": "시스템 설정에 있는 인터넷 시간 설정에서 박스를 체크하세요. 자세한 것은 다음의 가이드를 참조하세요: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "시간 동기화 서버를 가동시키기 위해서는 \"ntp\" 를 \"apt-get install ntp\" 명령으로 설치하세요.", + "darwin": "시간 동기화를 위해서, 시간 옵션을 열고 \"시간과 날짜 자동설정(Set the time and date automatically)\" 옵션을 선택하세요." + }, + "nodeChecksumMismatch": { + "title": "다운로드 한 노드에서 체크섬 불일치!", + "description": "__algorithm__: __hash__\n\n수동으로 __type__ 노드 버전 __version__을 설치해주세요." + }, + "legacyChain": { + "title": "레거시 체인 감지", + "description": "노드가 현재 지원되지 않는 이더리움 클래식 체인에 있습니다." + } + }, + "rightClick": { + "reload": "재로딩", + "openDevTools": "개발도구 열기", + "inspectElements": "요소 검사" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ 블록 남음", + "blockReceivedShort": "새 블록을 받았음", + "blockNumber": "마지막 블록 번호", + "timeSinceBlock": "마지막 블록 이후 경과시간", + "testnetExplain": "현재 테스트넷 상에 있습니다. 진짜 ERE을 이 주소로 절대 보내지 마세요.", + "peers": "피어들(peers)", + "checkingWhichNetwork": "네트워크 확인중...", + "privateNetwork": "프라이빗 네트워크" + }, + "sidebar": { + "buttons": { + "browser": "열람" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "계정을 선택하지 않음", + "connect": "연결" + } + }, + "startScreen": { + "runningNodeFound": "작동 중인 EtherCore 노드를 발견!", + "nodeConnectionTimeout": "EtherCore 노드를 시작할 수 없습니다!
만일Geth 를 설치 했다면, 다음의 명령어를 실행하세요:
geth --ipcpath __path__

또는 이슈를 보고하세요 ", + "nodeBinaryNotFound": "EtherCore 노드 실행파일이 없습니다!
수동으로 이를 먼저 실행하세요. ", + "nodeSyncing": "EtherCore 노드에 동기화가 필요합니다, 기다려 주세요...", + "nodeSyncInfo": "현재 __highestBlock__ 중 __currentBlcok__ 을 다운로드중", + "nodeSyncConnecting": "피어(peer)를 탐색하고 있는 중...", + "nodeStarting": "EtherCore 노드를 시작중...", + "nodeStarted": "EtherCore 노드가 시작됨", + "nodeConnected": "EtherCore 노드가 연결됨", + "nodeStopping": "EtherCore 노드가 정지중...", + "nodeStopped": "EtherCore 노드가 정지됨", + "nodeError": "EtherCore 노드 연결 에러 :'(", + "unableToBindPort": "EtherCore 노드를 실행 할 수 없습니다. 다른 인스턴스가 실행중인가요?", + "nodeSyncInfoStates": "블록 다운로드 중 __highestBlock__ 중 __displayBlock__,
체인구조 다운로드 __displayKnownStates__ 중 __displayState__", + "nodeSyncFoundPeers": "__peers__ 피어에 연결중...", + "launchApp": "어플리케이션 실행", + "clientBinaries": { + "scanning": "노드 업데이트 확인중...", + "downloading": "새로운 노드 다운로드중...", + "loadConfig": "클라이언트 설정 로딩중...", + "filtering": "클라이언트 바이너리 필터링중...", + "done": "EtherCore 노드 최신버전...", + "error": "다운로드 된 바이너리 실행 중 오류." + } + }, + "popupWindows": { + "requestAccount": { + "title": "계정 만들기", + "enterPassword": "암호를 입력하세요", + "repeatPassword": "암호를 다시 입력하세요", + "creating": "계정 만드는 중...", + "errors": { + "passwordMismatch": "암호가 일치하지 않습니다.", + "passwordTooShort": "암호가 너무 짧습니다." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "트랜잭션 보내기", + "contractExecution": "계약 실행", + "createContract": "계약 만들기" + }, + "contractExecutionInfo": "계약 상의 함수를 실행시키려고 합니다. 가치 전송이 일어날 수도 있습니다.", + "contractCreationInfo": "주어진 데이터를 가지고 계약을 만들려고 합니다.", + "enterPassword": "트랜잭션을 확인하기 위해 암호를 입력하세요", + "unlocking": "확인 중...", + "createContract": "계약 만들기", + "estimatedFee": "예상 수수료 사용량", + "estimatedGasError": "트랜젝션을 실패할 수 있습니다. 그래도 전송하면 제공된 개스는 모두 소진될 수 있습니다.", + "gasPrice": "개스 가격", + "perMillionGas": "백만 개스당 ERE수", + "gasLimit": "최고 수수료 제공", + "data": "데이터", + "buttons": { + "sendTransaction": "트랜잭션 보내기" + }, + "errors": { + "connectionTimeout": "노드에 연결할 수 없었습니다. 백그라운드에서 작동 중지되었습니까?", + "wrongPassword": "암호가 일치하지 않습니다", + "multipleKeysMatchAddress": "여러 개의 키가 주소와 일치합니다. 키 스토어에서 중복 된 것을 제거하십시오. (메뉴 -> 계정 -> 백업 -> 계정)", + "insufficientFundsForGas": "주 계정(etherbase)에 가스를 지불할 금액이 충분하지 않습니다.", + "sameAccount": "현재 사용하고 있는 계정으로 전송할 수 없습니다" + }, + "transactionThrow": "이 계약은 트랜젝션을 승인하지 않을 것 입니다.", + "noEstimate": "가스 소모량을 추정 할 수 없습니다.", + "parameters": "파라미터", + "showRawBytecode": "원 데이터 보기", + "showDecodedParameters": "디코딩된 파라미터 보기", + "lookupData": "데이터 디코딩하기", + "lookupDataExplainer": "해당 내용을 인터넷에서 확인하세요", + "overBlockGasLimit": "이 실행에 필요한 가스는 블록 가스 제한을 초과 할 수 있습니다.", + "notEnoughGas": "가스가 이 거래를 성공적으로 끝내기에 충분하지 않을 수 있습니다.
여기를 클릭해서 가스를 늘리세요" + }, + "onboarding": { + "description": "EtherCore은 블록체인상에 앱을 만들기 위한 탈중앙화된 플랫폼이며, 이 블록체인은 변조방지가능한 소프트웨어로서 가치와 자산을 전송할 수 있고 영구히 존속합니다.", + "goToTestnet": "테스트 네트워크 사용하기 (Rinkeby)", + "goToTestnetDescription": "샌드박스 테스트넷에서 실제 ERE을 사용하지 않고 자유롭게 테스트하기.", + "gotoMainnet": "메인 네트워크 사용하기", + "gotoMainnetDescription": "계약을 만들고 사용하기 위해서는 약간의 ERE이 필요합니다. 약간의 ERE을 가질 수 있도록 도와줄 수 있습니다.", + "doYouHaveAWalletFile": "지갑 파일을 가지고 있나요?", + "walletFileDescription": "

만일 2014년 이더리움 프리세일에 참여했다면, ethereum_wallet_backup.json 이란 파일을 가지고 있을 겁니다. 세일이 끝나고 다운로드를 받았거나 이메일로 받았을 겁니다.

", + "dropFilesHere": "프리세일 파일을 가져다 놓기", + "creating": "만드는 중...", + "importing": "불러오는 중...", + "skip": "이 단계 건너뛰기", + "next": "다음", + "protectTitle": "계정 보호", + "protectDescription": "새 계정를 위한 암호를 선택하세요. 집열쇠를 보관하듯이 강력한 암호를 선택하세요!", + "accountTitle": "구동 시작!", + "accountTitleTestnet": "채굴 성공!", + "etherDescription": "EtherCore은 'ERE'이라는 토큰을 기반으로 하고 있습니다. EtherCore을 사용하기 위해서는 약간의 ERE이 필요하게 될 것입니다.", + "loadItDescription": "만일 비트코인이나 다른 암호화 화폐를 가지고 있다면, changelly를 이용해 손쉽게 이더로 바꿀 수 있습니다.

0.25 to 1 ether 이더 정도를 바꿀 것을 추천합니다.", + "mineItDescription": "테스트넷상에서는 개발 메뉴에 있는 채굴 시작을 선택함으로써 이더를 채굴할 수 있습니다.
이 주소로 진짜 이더를 절대 보내지 마세요.", + "you": "당신", + "etherbase": "주 계정(Main account)", + "depositBitcoin": "비트코인 송금", + "learnIt": "기다리는 동안 학습하기", + "downloadingBlocks": "블록 다운로드 중", + "tutorial1Description": "

이제 남은 것은 다운로드가 끝날 때까지 기다리는 것입니다. 여기에 읽어볼 내용들이 있습니다:

여려분 자신의 화폐 만들기

실제 자산을 표현하는 제한된 공급을 가진 암호화 화폐만들기 등등,

", + "tutorial2Description": "

크라우드세일 만들기

제3자 없이 완벽히 신뢰할 수 공동의 목표를 위한 펀드 조성. 전통적인 펀딩에서 발생하는 여러가지 장벽들을 피해서, 블록체인을 사용해서 직접 대상조직에 펀딩.

", + "tutorial3Description": "

블록체인 조직

어떻게 자금이 사용되고, 누가 결정권을 가게 될지 등에 대한 위반할 수 없는 룰들을 가진 자율 조직을 만들 수 있습니다. 어떻게 자금이 사용되어야 할지에 대해 당신의 지지자들에게 적극적인 역할을 부여하세요.

", + "buttons": { + "showPassword": "암호보기" + }, + "errors": { + "unknownFile": "파일을 인식할 수 없습니다.", + "wrongPassword": "암호가 틀렸습니다.", + "importFailed": "파일을 가져올 수 없습니다: __error__" + } + }, + "updateAvailable": { + "newVersionAvailable": "새 버전 __name__ 사용가능", + "version": "버전", + "downloadURL": "다운로드 URL", + "checksum": "체크섬", + "downloadAndRestart": "업데이트 후 재시동", + "download": "새 버전 다운로드", + "skipUpdate": "업데이트 건너뛰기", + "checking": "__name__ 업데이트 확인중 ...", + "noUpdateFound": "업데이트가 없습니다. 최신 버전의 __name__ 를 사용하고 있습니다." + }, + "connectAccount": { + "chooseAccountTitle": "계정 선택", + "createAccount": "새 계정 생성", + "pinToSidebar": "사이드바에 앱 고정", + "connectAccountDescription": "당신의 프로필은 __dappName__에 공유됩니다. 이를 통해 다른 사람들이 연결된 잔액을 포함하여 계정의 모든 공개 정보를 앱에서 볼 수 있습니다." + } + } + }, + "elements": { + "checksumAlert": "이 주소는 유효해보이지만, 오타 등의 실수로부터 당신을 보호할 수 있는 보안기능이 없습니다. 다시 한 번 맞는지 확인해 보시기 바랍니다. 보안 아이콘이 있는 경우 이것이 일치하는지 확인하시기 바랍니다.", + "identiconHelper": "이것은 보안 아이콘입니다. 주소에 어떤 변화라도 생기면, 이 아이콘은 완전히 다른 모양으로 변합니다.", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.kr.i18n.json b/interface/i18n/mist.kr.i18n.json new file mode 100644 index 0000000..2f63250 --- /dev/null +++ b/interface/i18n/mist.kr.i18n.json @@ -0,0 +1,251 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "__app__에 대하여", + "checkForUpdates": "업데이트 확인...", + "checkForNodeUpdates": "EtherCore 노드 업데이트 확인...", + "services": "서비스", + "hide": "__app__ 숨기기", + "hideOthers": "다른 창 숨기기", + "showAll": "모두 보기", + "quit": "__app__ 종료" + }, + "edit": { + "label": "수정", + "undo": "되돌리기", + "redo": "재적용", + "cut": "오려두기", + "copy": "복사하기", + "paste": "붙이기", + "selectAll": "모두 선택" + }, + "view": { + "label": "보기", + "fullscreen": "전체화면으로", + "default": "기본" + }, + "file": { + "label": "계정", + "importPresale": "계정 추가하기", + "newAccount": "새 계정", + "backup": "백업", + "backupKeyStore": "계정키 백업", + "backupMist": "어플리케이션 데이터", + "swarmUpload": "Swarm에 업로드" + }, + "develop": { + "label": "개발", + "devTools": "개발도구 전환", + "devToolsMistUI": "미스트 UI", + "devToolsWalletUI": "지갑 UI", + "devToolsWebview": "__webview__", + "runTests": "테스트 실행", + "logFiles": "로그파일 보기", + "ethereumNode": "EtherCore 노드", + "network": "네트워크", + "mainNetwork": "메인 네트워크", + "startMining": "⛏ 채굴 시작(테스트넷만 해당)", + "stopMining": "⛏ 채굴 중단", + "openRemix": "Remix IDE 열기" + }, + "window": { + "label": "창", + "minimize": "최소화", + "close": "닫기", + "toFront": "전면으로 보내기" + }, + "help": { + "label": "도움말", + "reportBug": "깃허브에 이슈 보고" + } + }, + "errors": { + "nodeConnect": "노드에 연결할 수 없습니다? 자세한 것은 로그를 확인하세요:", + "nodeStartup": "노드가 시작하지 못하고 있습니다. 이미 다른 노드를 실행하고 있거나 현재 데이터베이스를 업그레이드 하고 있나요?", + "timeSync": { + "title": "당신의 컴퓨터 시간이 동기화되어 있지 않습니다.", + "description": "EtherCore 네트워크와 성공적으로 동기화하기 위해서는 사용하시는 컴퓨터의 시간을 시간서버와 동기화해야 합니다.", + "win32": "시스템 설정에 있는 인터넷 시간 설정에서 박스를 체크하세요. 자세한 것은 다음의 가이드를 참조하세요: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "시간 동기화 서버를 가동시키기 위해서는 \"ntp\" 를 \"apt-get install ntp\" 명령으로 설치하세요.", + "darwin": "시간 동기화를 위해서, 시간 옵션을 열고 \"시간과 날짜 자동설정(Set the time and date automatically)\" 옵션을 선택하세요." + }, + "nodeChecksumMismatch": { + "title": "다운로드 한 노드에서 체크섬 불일치!", + "description": "__algorithm__: __hash__\n\n수동으로 __type__ 노드 버전 __version__을 설치해주세요." + }, + "legacyChain": { + "title": "레거시 체인 감지", + "description": "노드가 현재 지원되지 않는 이더리움 클래식 체인에 있습니다. 이 체인을 사용하려면 이더리움 클래식 프로젝트에서 제공하는 도구를 사용하십시오.\nhttps://ethereumclassic.github.io.\n\n이더리움 체인으로 되돌리려면 튜토리얼을 살펴보세요.:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "재로딩", + "openDevTools": "개발도구 열기", + "inspectElements": "요소 검사" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ 블록 남음", + "blockReceivedShort": "새 블록을 받았음", + "blockNumber": "마지막 블록 번호", + "timeSinceBlock": "마지막 블록 이후 경과시간", + "testnetExplain": "현재 테스트넷 상에 있습니다. 진짜 ERE을 이 주소로 절대 보내지 마세요.", + "peers": "피어들(peers)", + "checkingWhichNetwork": "네트워크 확인중...", + "privateNetwork": "프라이빗 네트워크" + }, + "sidebar": { + "buttons": { + "browser": "열람" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "계정을 선택하지 않음", + "connect": "연결" + } + }, + "startScreen": { + "runningNodeFound": "작동 중인 EtherCore 노드를 발견!", + "nodeConnectionTimeout": "EtherCore 노드를 시작할 수 없습니다!
만일Geth 를 설치 했다면, 다음의 명령어를 실행하세요:
geth --ipcpath __path__

또는 이슈를 보고하세요 ", + "nodeBinaryNotFound": "EtherCore 노드 실행파일이 없습니다!
수동으로 이를 먼저 실행하세요. ", + "nodeSyncing": "EtherCore 노드에 동기화가 필요합니다, 기다려 주세요...", + "nodeSyncInfo": "현재 __highestBlock__ 중 __currentBlcok__ 을 다운로드중", + "nodeSyncConnecting": "피어(peer)를 탐색하고 있는 중...", + "nodeStarting": "EtherCore 노드를 시작중...", + "nodeStarted": "EtherCore 노드가 시작됨", + "nodeConnected": "EtherCore 노드가 연결됨", + "nodeStopping": "EtherCore 노드가 정지중...", + "nodeStopped": "EtherCore 노드가 정지됨", + "nodeError": "EtherCore 노드 연결 에러 :'(", + "unableToBindPort": "EtherCore 노드를 실행 할 수 없습니다. 다른 인스턴스가 실행중인가요?", + "nodeSyncInfoStates": "블록 다운로드 중 __highestBlock__ 중 __displayBlock__,
체인구조 다운로드 __displayKnownStates__ 중 __displayState__", + "nodeSyncFoundPeers": "__peers__ 피어에 연결중...", + "launchApp": "어플리케이션 실행", + "clientBinaries": { + "scanning": "노드 업데이트 확인중...", + "downloading": "새로운 노드 다운로드중...", + "loadConfig": "클라이언트 설정 로딩중...", + "filtering": "클라이언트 바이너리 필터링중...", + "done": "EtherCore 노드 최신버전...", + "error": "다운로드 된 바이너리 실행 중 오류." + } + }, + "popupWindows": { + "requestAccount": { + "title": "계정 만들기", + "enterPassword": "암호를 입력하세요", + "repeatPassword": "암호를 다시 입력하세요", + "creating": "계정 만드는 중...", + "errors": { + "passwordMismatch": "암호가 일치하지 않습니다.", + "passwordTooShort": "암호가 너무 짧습니다." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "트랜잭션 보내기", + "contractExecution": "계약 실행", + "createContract": "계약 만들기" + }, + "contractExecutionInfo": "계약 상의 함수를 실행시키려고 합니다. 가치 전송이 일어날 수도 있습니다.", + "contractCreationInfo": "주어진 데이터를 가지고 계약을 만들려고 합니다.", + "enterPassword": "트랜잭션을 확인하기 위해 암호를 입력하세요", + "unlocking": "확인 중...", + "createContract": "계약 만들기", + "estimatedFee": "예상 수수료 사용량", + "estimatedGasError": "트랜젝션을 실패할 수 있습니다. 그래도 전송하면 제공된 개스는 모두 소진될 수 있습니다.", + "gasPrice": "개스 가격", + "perMillionGas": "백만 개스당 ERE수", + "gasLimit": "최고 수수료 제공", + "data": "데이터", + "buttons": { + "sendTransaction": "트랜잭션 보내기" + }, + "errors": { + "connectionTimeout": "노드에 연결할 수 없었습니다. 백그라운드에서 작동 중지되었습니까?", + "wrongPassword": "암호가 일치하지 않습니다", + "multipleKeysMatchAddress": "여러 개의 키가 주소와 일치합니다. 키 스토어에서 중복 된 것을 제거하십시오. (메뉴 -> 계정 -> 백업 -> 계정)", + "insufficientFundsForGas": "주 계정(EtherCore)에 가스를 지불할 금액이 충분하지 않습니다.", + "sameAccount": "현재 사용하고 있는 계정으로 전송할 수 없습니다" + }, + "transactionThrow": "이 계약은 트랜젝션을 승인하지 않을 것 입니다.", + "noEstimate": "가스 소모량을 추정 할 수 없습니다.", + "parameters": "파라미터", + "showRawBytecode": "원 데이터 보기", + "showDecodedParameters": "디코딩된 파라미터 보기", + "lookupData": "데이터 디코딩하기", + "lookupDataExplainer": "해당 내용을 인터넷에서 확인하세요", + "overBlockGasLimit": "이 실행에 필요한 가스는 블록 가스 제한을 초과 할 수 있습니다.", + "notEnoughGas": "가스가 이 거래를 성공적으로 끝내기에 충분하지 않을 수 있습니다.
여기를 클릭해서 가스를 늘리세요" + }, + "onboarding": { + "description": "EtherCore은 블록체인상에 앱을 만들기 위한 탈중앙화된 플랫폼이며, 이 블록체인은 변조방지가능한 소프트웨어로서 가치와 자산을 전송할 수 있고 영구히 존속합니다.", + "goToTestnet": "테스트 네트워크 사용하기 (Rinkeby)", + "goToTestnetDescription": "샌드박스 테스트넷에서 실제 ERE을 사용하지 않고 자유롭게 테스트하기.", + "gotoMainnet": "메인 네트워크 사용하기", + "gotoMainnetDescription": "계약을 만들고 사용하기 위해서는 약간의 ERE이 필요합니다. 약간의 ERE을 가질 수 있도록 도와줄 수 있습니다.", + "doYouHaveAWalletFile": "지갑 파일을 가지고 있나요?", + "walletFileDescription": "

만일 2014년 이더리움 프리세일에 참여했다면, ethereum_wallet_backup.json 이란 파일을 가지고 있을 겁니다. 세일이 끝나고 다운로드를 받았거나 이메일로 받았을 겁니다.

", + "dropFilesHere": "프리세일 파일을 가져다 놓기", + "creating": "만드는 중...", + "importing": "불러오는 중...", + "skip": "이 단계 건너뛰기", + "next": "다음", + "protectTitle": "계정 보호", + "protectDescription": "새 계정를 위한 암호를 선택하세요. 집열쇠를 보관하듯이 강력한 암호를 선택하세요!", + "accountTitle": "구동 시작!", + "accountTitleTestnet": "채굴 성공!", + "etherDescription": "EtherCore은 'ERE'이라는 토큰을 기반으로 하고 있습니다. EtherCore을 사용하기 위해서는 약간의 ERE이 필요하게 될 것입니다.", + "loadItDescription": "만일 비트코인이나 다른 암호화 화폐를 가지고 있다면, changelly를 이용해 손쉽게 이더로 바꿀 수 있습니다.

0.25 to 1 ether 이더 정도를 바꿀 것을 추천합니다.", + "mineItDescription": "테스트넷상에서는 개발 메뉴에 있는 채굴 시작을 선택함으로써 이더를 채굴할 수 있습니다.
이 주소로 진짜 이더를 절대 보내지 마세요.", + "you": "당신", + "etherbase": "주 계정(Main account)", + "depositBitcoin": "비트코인 송금", + "learnIt": "기다리는 동안 학습하기", + "downloadingBlocks": "블록 다운로드 중", + "tutorial1Description": "

이제 남은 것은 다운로드가 끝날 때까지 기다리는 것입니다. 여기에 읽어볼 내용들이 있습니다:

여려분 자신의 화폐 만들기

실제 자산을 표현하는 제한된 공급을 가진 암호화 화폐만들기 등등,

", + "tutorial2Description": "

크라우드세일 만들기

제3자 없이 완벽히 신뢰할 수 공동의 목표를 위한 펀드 조성. 전통적인 펀딩에서 발생하는 여러가지 장벽들을 피해서, 블록체인을 사용해서 직접 대상조직에 펀딩.

", + "tutorial3Description": "

블록체인 조직

어떻게 자금이 사용되고, 누가 결정권을 가게 될지 등에 대한 위반할 수 없는 룰들을 가진 자율 조직을 만들 수 있습니다. 어떻게 자금이 사용되어야 할지에 대해 당신의 지지자들에게 적극적인 역할을 부여하세요.

", + "buttons": { + "showPassword": "암호보기" + }, + "errors": { + "unknownFile": "파일을 인식할 수 없습니다.", + "wrongPassword": "암호가 틀렸습니다.", + "importFailed": "파일을 가져올 수 없습니다: __error__" + } + }, + "updateAvailable": { + "newVersionAvailable": "새 버전 __name__ 사용가능", + "version": "버전", + "downloadURL": "다운로드 URL", + "checksum": "체크섬", + "downloadAndRestart": "업데이트 후 재시동", + "download": "새 버전 다운로드", + "skipUpdate": "업데이트 건너뛰기", + "checking": "__name__ 업데이트 확인중 ...", + "noUpdateFound": "업데이트가 없습니다. 최신 버전의 __name__ 를 사용하고 있습니다." + }, + "connectAccount": { + "chooseAccountTitle": "계정 선택", + "createAccount": "새 계정 생성", + "pinToSidebar": "사이드바에 앱 고정", + "connectAccountDescription": "당신의 프로필은 __dappName__에 공유됩니다. 이를 통해 다른 사람들이 연결된 잔액을 포함하여 계정의 모든 공개 정보를 앱에서 볼 수 있습니다." + } + } + }, + "elements": { + "checksumAlert": "이 주소는 유효해보이지만, 오타 등의 실수로부터 당신을 보호할 수 있는 보안기능이 없습니다. 다시 한 번 맞는지 확인해 보시기 바랍니다. 보안 아이콘이 있는 경우 이것이 일치하는지 확인하시기 바랍니다.", + "identiconHelper": "이것은 보안 아이콘입니다. 주소에 어떤 변화라도 생기면, 이 아이콘은 완전히 다른 모양으로 변합니다.", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.nb.i18n.json b/interface/i18n/mist.nb.i18n.json new file mode 100644 index 0000000..786c25a --- /dev/null +++ b/interface/i18n/mist.nb.i18n.json @@ -0,0 +1,282 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "Om __app__", + "checkForUpdates": "Se etter oppdateringer...", + "checkForNodeUpdates": "Check for Ethereum node updates...", + "services": "Tjenester", + "hide": "Skjul __app__", + "hideOthers": "Skjul Andre", + "showAll": "Vis Alle", + "quit": "Avslutt __app__" + }, + "edit": { + "label": "Endre", + "undo": "Angre", + "redo": "Gjenta", + "cut": "Klipp", + "copy": "Kopier", + "paste": "Lim inn", + "selectAll": "Velg alt" + }, + "view": { + "label": "Vis", + "fullscreen": "Veksle Mellom Fullskjerm", + "default": "Default" + }, + "file": { + "label": "Kontoer", + "importPresale": "Importer Kontoer", + "newAccount": "Ny konto", + "backup": "Sikkerhetskopier", + "backupKeyStore": "Kontoer", + "backupMist": "Applikasjonsdata" + }, + "develop": { + "uploadToSwarm": "Opplasting til Swarm", + "label": "Utvikle", + "devTools": "Veksle Mellom Utviklerverktøy", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Lommebok UI", + "devToolsWebview": "__webview__", + "runTests": "Kjør tester", + "logFiles": "Vis loggfil", + "ethereumNode": "Ethereum Node", + "network": "Nettverk", + "mainNetwork": "Hovednettverk", + "startMining": "⛏ Start Mining", + "stopMining": "⛏ Stopp Mining", + "externalNode": "using external node", + "openRemix": "Open Remix IDE", + "nodeMode": "Chain download", + "fullNode": "Store full blockchain", + "lightNode": "Use light Node (experimental!)" + }, + "window": { + "label": "Vindu", + "minimize": "Minimer", + "close": "Lukk", + "toFront": "Legg Alle I Forgrunnen" + }, + "help": { + "label": "Hjelp", + "reportBug": "Report an issue on Github" + } + }, + "errors": { + "nodeConnect": "Kunne ikke koble til node? Se logger for mer:", + "nodeStartup": "Det virker som noden ikke kunne startes, har du allerede en som kjører? Oppgraderer den databasen akkurat nå?", + "timeSync": { + "title": "Datamaskinens klokke er ikke synkronisert.", + "description": "For å kunne synkronisere med Ethereum-nettverket trenger du å synkronisere datamaskinens klokke med en tidssynkroniseringsserver.", + "win32": "Gå til tidsinnstillinger for internett i systeminnstillinger og kryss av i boksen. Se denne guiden for detaljer: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "For å aktivere en tidssynkroniseringsserver installer \"ntp\" via \"apt-get install ntp\".", + "darwin": "For å aktivere tidssynkronisering, åpne tidsinnstillinger og velg \"Angi klokkeslett og dato automatisk\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in downloaded node!", + "description": "__algorithm__: __hash__\n\nPlease install the __type__ node version __version__ manually." + }, + "legacyChain": { + "title": "Legacy chain detected", + "description": "Your node is currently on the unsupported Ethereum Classic chain. To use this chain use tools provided by the ethereum classic project at\nhttps://ethereumclassic.github.io.\n\nTo revert to the main ethereum chain follow the tutorial here:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Last", + "openDevTools": "Åpne Utviklerverktøy", + "inspectElements": "Inspiser Element" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ blokker igjen", + "blockReceived": "Ny Blokk Mottatt", + "blockNumber": "Det siste blokknummeret", + "timeSinceBlock": "Tid siden siste blokk", + "checkingWhichNetwork": "Kontrollerer nettverk...", + "mainNetwork": "Hovednett", + "testNetwork": "Testnett", + "privateNetwork": "Privatnett", + "mainnetExplain": "Du er på det globale Ethereum hovednettverket", + "testnetExplain": "Du er på testnettet, IKKE SEND noen ekte ether til disse adressene", + "privatenetExplain": "Du er på et privatnett, IKKE SEND noen ekte ether til disse adressene", + "unknownnetExplain": "Kan ikke fastslå hvilket nettverk du er på", + "peers": "peers" + }, + "sidebar": { + "buttons": { + "browser": "Bla gjennom" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "Ingen kontoer satt", + "connect": "Connect" + } + }, + "startScreen": { + "runningNodeFound": "Fant kjørende Ethereum-node!", + "startingNode": "Starter Ethereum-node...", + "stoppingNode": "Stopper Ethereum-node...", + "startedNode": "Starter applikasjonen...", + "nodeConnectionTimeout": "Kunne ikke starte Ethereum-node!
Hvis du installerte Geth, bruk denne kommandoen for å kjøre det:
geth --ipcpath __path__

Eller rapporter et problem ", + "nodeBinaryNotFound": "Ingen Ethereum-node kilde funnet!
Vennligst start en manuelt først. ", + "nodeStarting": "Ethereum-node starter opp...", + "nodeStarted": "Ethereum-node startet", + "nodeConnected": "Ethereum-node tilkoblet", + "nodeStopping": "Ethereum-node stopper...", + "nodeStopped": "Ethereum-node stoppet", + "nodeError": "Ethereum-node tilkoblingsfeil :'(", + "unableToBindPort": "Ethereum-node kan ikke kjøre. Kjører det en allerede?", + "nodeSyncing": "Ethereum-node trenger å synkroniseres, vennligst vent...", + "nodeSyncInfo": "Laster ned blokk __currentBlock__ av __highestBlock__.", + "nodeSyncConnecting": "Leter etter peers...", + "peerSearchTimeout": "Hopp over peer søk", + "launchApp": "Start Applikasjonen", + "nodeSyncInfoStates": "Downloading block __displayBlock__ of __highestBlock__,
Downloading chain structure __displayState__ of __displayKnownStates__", + "nodeSyncFoundPeers": "Connecting to __peers__ peers...", + "clientBinaries": { + "scanning": "Checking for node update...", + "downloading": "Downloading new node...", + "loadConfig": "Loading client config...", + "filtering": "Filtering client binaries...", + "done": "Ethereum node up-to-date...", + "error": "Error running downloaded binary." + } + }, + "popupWindows": { + "requestAccount": { + "title": "Lag konto", + "enterPassword": "Oppgi passord", + "repeatPassword": "Gjenta passord", + "creating": "Genererer konto...", + "errors": { + "passwordMismatch": "Passordene stemmer ikke overens.", + "passwordTooShort": "Make a longer password" + } + }, + "unlockMasterPassword": { + "title": "Oppgi hovedpassordet", + "enterPassword": "Oppgi hovedpassordet", + "unlocking": "Låser opp...", + "errors": { + "wrongPassword": "Passordet er feil, prøv igjen." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Send transaksjon", + "contractExecution": "Utfør kontrakt", + "createContract": "Lag kontrakt" + }, + "contractExecutionInfo": "Du er i ferd med å utføre en funksjon på en kontrakt. Dette kan innebære overføring av verdier.", + "contractCreationInfo": "Du er i ferd med å lage en kontrakt fra de oppgitte data.", + "enterPassword": "Skriv inn passord for å bekrefte transaksjonen", + "unlocking": "Bekrefter...", + "createContract": "Lag kontrakt", + "estimatedFee": "Beregnet avgiftsforbruk", + "estimatedGasError": "Data kan ikke utføres, så den kommer til å bruke all gass.", + "gasPrice": "Gass pris", + "perMillionGas": "ether per million gass", + "gasLimit": "Gi maksimal avgift", + "data": "Data", + "buttons": { + "sendTransaction": "Send transaksjon" + }, + "errors": { + "connectionTimeout": "Kunne ikke koble til noden, krasjet den i bakgrunnen?", + "wrongPassword": "Feil passord", + "multipleKeysMatchAddress": "Multiple keys match address. Please remove duplicates from keystore (menu -> File -> Backup -> Accounts)", + "insufficientFundsForGas": "Insufficient funds in main account (etherbase) to pay for gas", + "sameAccount": "Can't send to itself" + }, + "transactionThrow": "The contract won't allow this transaction to be executed", + "noEstimate": "We couldn't estimate the gas.", + "parameters": "Parameters", + "showRawBytecode": "show raw data", + "showDecodedParameters": "show decoded parameters", + "lookupData": "Try to decode data", + "lookupDataExplainer": "Look this up on the internet", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount." + }, + "onboarding": { + "description": "Ethereum er en desentralisert plattform for å bygge applikasjoner på en blokkjede: sabotasjesikker programvare som kan overføre verdi og eiendom, og som lever evig", + "goToTestnet": "Bruk testnettet (Rinkeby)", + "goToTestnetDescription": "Test teknologien fritt i en sandboks (testnett), uten å bruke ekte ether.", + "gotoMainnet": "Bruk hovednettverket", + "gotoMainnetDescription": " Du trenger noen ether for å skape og utføre kontrakter. Ikke bekymre deg, vi vil hjelpe deg å skaffe noen...", + "doYouHaveAWalletFile": "Har du en lommebok-fil?", + "walletFileDescription": "

Hvis du har deltatt på forhåndssalget av Ethereum i 2014, har du en fil med navnet ethereum_wallet_backup.json. Den ble lastet ned etter salget, og også sendt til din e-post

", + "dropFilesHere": "Slipp filen fra forhåndssalget", + "creating": "Lager...", + "importing": "Importerer...", + "skip": "Hopp over dette steget", + "next": "Neste", + "protectTitle": "Beskytt kontoen din", + "protectDescription": "Velg et passord for den nye kontoen. Gjør det så sterkt som om det skulle beskyttet husnøklene dine!", + "accountTitle": "Fyll den opp!", + "accountTitleTestnet": "Mine noen!", + "etherDescription": "Ethereum-nettverket er basert på en enhet kalt \"ether\". Du trenger en liten mengde av den for å gjøre noe på Ethereum-nettverket.", + "loadItDescription": "Hvis du allerede eier bitcoin, eller hvilken som helst annen kryptovaluta, kan du enkelt konvertere den til ether via changelly.

Vi anbefaler å fylle opp med mellom 0.25 til 1 ether.", + "mineItDescription": "På testnettet kan du mine ether selv ved å gå til Utvikle menyvalget og velge Start Mining.
IKKE PRØV Å SENDE EKTE ETHER TIL DENNE ADRESSEN ", + "you": "DU", + "etherbase": "Hovedkonto (etherbase)", + "depositBitcoin": "Sett inn bitcoin", + "learnIt": "Lær mens du venter", + "downloadingBlocks": "Laster ned blokker", + "tutorial1Description": "

Nå er den eneste tingen igjen er å vente til nedlastingen er ferdig. Her er noen lesetips:

Lag dine egne penger

Lag en kryptovaluta med en fast pengemengde, enhet som representerer verdier i den virkelige verden, etc

", + "tutorial2Description": "

Lag et crowdsale

Samle inn penger til et felles mål, på en sikker måte uten en tredjepart. Omgå hinder i det tradisjonelle finansieringssystemet, og gå direkte til kilden ved å finansiere en organisasjon via blokkjeden.

", + "tutorial3Description": "

Organisasjon på Blokkjeden

Lag en autonom organisasjon med uknuselige regler om hvordan pengene kan bli brukt og hvem som kan ta beslutningene. La dine støttespillere ta en aktiv rolle i hvordan pengene blir brukt

", + "buttons": { + "showPassword": "Vis passord", + "importAccount": "Importer konto", + "launchApp": "Start Applikasjonen!", + "learnReceipt": "Lær denne oppskriften" + }, + "errors": { + "nodeNotStartedYet": "Vent noen sekunder til noden er fullt i gang og prøv igjen", + "unknownFile": "Fil ikke gjenkjent.", + "wrongPassword": "Feil passord.", + "importFailed": "Kunne ikke importere filen, fikk: __error__" + }, + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "syncMessage": "Block __displayBlock__ of __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ of __highestBlockString__ (Chain structure __statesPercent__%)", + "startingSync": "Getting ready to sync.." + }, + "updateAvailable": { + "newVersionAvailable": "New __name__ version available", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Update and Restart", + "download": "Download new version", + "skipUpdate": "Skip Update", + "notNow": "Ask me later", + "checking": "Checking for updates to __name__...", + "noUpdateFound": "No update found. You are running the latest version of __name__." + }, + "connectAccount": { + "chooseAccountTitle": "Choose account", + "createAccount": "Create new account", + "pinToSidebar": "Pin app to the sidebar", + "connectAccountDescription": "You are sharing your identity with __dappName__. This allows the app to see any public information of your accounts, including balances connected to it." + } + } + }, + "elements": { + "checksumAlert": "Denne adressen ser gyldig ut, men den har ikke sikkerhetsfunksjonen som vil beskytte deg mot skrivefeil, så dobbeltsjekk at den er rett. Hvis det er mulig, sjekk om sikkerhetsikonet stemmer overens.", + "identiconHelper": "Dette er et sikkerhetsikon. Hvis det er noen endring på adressen vil resultatet gi et ikon som ser helt annerledes ut", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.nl.i18n.json b/interface/i18n/mist.nl.i18n.json new file mode 100644 index 0000000..503b0da --- /dev/null +++ b/interface/i18n/mist.nl.i18n.json @@ -0,0 +1,300 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "Over __app__", + "checkForUpdates": "Op updates controleren...", + "checkForNodeUpdates": "Controleer op Ethereum node updates...", + "services": "Diensten", + "hide": "__app__ verbergen", + "hideOthers": "Andere verbergen", + "showAll": "Alles weergeven", + "quit": "__app__ afsluiten" + }, + "edit": { + "label": "Bewerken", + "undo": "Ongedaan maken", + "redo": "Overdoen", + "cut": "Knippen", + "copy": "Kopieren", + "paste": "Plakken", + "selectAll": "Alles selecteren" + }, + "view": { + "label": "Weergave", + "fullscreen": "Volledig Scherm Inschakelen", + "languages": "Wijzig taal", + "default": "Standaard", + "langCodes": { + "de": "Deutsch", + "en": "English", + "es": "Español", + "fa": "فارسى", + "fr": "Français", + "it": "Italiano", + "ja": "日本語", + "ko": "한국어 ", + "nl": "Nederlands", + "nb": "Norsk", + "pt": "Português", + "sq": "Shqip", + "ru": "Pусский", + "zh": "普通話", + "zh-TW": "國語" + } + }, + "file": { + "label": "Bestand", + "importPresale": "Importeer Accounts", + "newAccount": "Nieuw account", + "backup": "Backup", + "backupKeyStore": "Accounts", + "backupMist": "Applicatie Data" + }, + "develop": { + "uploadToSwarm": "Uploaden naar Swarm", + "label": "Ontwikkelen", + "devTools": "Ontwikkelaars Opties Inschakelen", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Wallet UI", + "devToolsWebview": "__webview__", + "runTests": "Tests uitvoeren", + "logFiles": "Toon log bestand", + "openRemix": "Open Remix IDE", + "externalNode": "Externe Node in gebruik", + "ethereumNode": "Ethereum Node", + "network": "Netwerk", + "nodeMode": "Chain download", + "fullNode": "Bewaar volledige blockchain", + "lightNode": "Gebruik light Node (experimenteel!)", + "mainNetwork": "Hoofdnetwerk", + "startMining": "⛏ Start Mining", + "stopMining": "⛏ Stop Mining" + }, + "window": { + "label": "Scherm", + "minimize": "Minimaliseer", + "close": "Sluiten", + "toFront": "Alles op voorgrond" + }, + "help": { + "label": "Help", + "reportBug": "Rapporteer een probleem op Github" + } + }, + "errors": { + "nodeConnect": "Verbinden met node niet mogelijk? Zie de logboek bestanden voor meer informatie:", + "nodeStartup": "Het lijkt erop dat de node niet kan worden opgestart, draait er al een? Is deze de database aan het upgraden?", + "timeSync": { + "title": "Je computer's klok is niet gesynchroniseerd.", + "description": "Om succesvol met het Ethereum netwerk te verbinden moet je computer's klok gesynchroniseerd zijn met een tijdssynchronisatie server.", + "win32": "Ga naar je Internet Tijd Instellingen in je configuratiescherm en selecteer de optie. Zie deze uitleg voor details: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "Installeer voor een tijdssynchronisatieserver \"ntp\" via \"apt-get install ntp\".", + "darwin": "Zet tijdssynchronisatie aan door in je instellingen de optie \"Tijd en datum automatisch instellen\" te activeren." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in gedownloade node!", + "description": "__algorithm__: __hash__\n\nInstalleer de __type__ node versie __version__ handmatig." + }, + "legacyChain": { + "title": "Legacy chain gedetecteerd", + "description": "Je node draait momenteel op de niet ondersteunde Ethereum Classic chain. Om deze chain te gebruiken dien je de tools te gebruiken van het Ethereum Classic project op\nhttps://ethereumclassic.github.io.\n\nOm terug te gaan naar de standaard Ethereum chain kun je deze tutorial volgen:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Herladen", + "openDevTools": "Open Ontwikkelaarstools", + "inspectElements": "Element Inspecteren" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ blokken te gaan", + "blockReceived": "Nieuw blok ontvangen", + "blockNumber": "Jouw laatste bloknummer", + "timeSinceBlock": "Verstreken tijd sinds laatste blok", + "checkingWhichNetwork": "Netwerk aan het controleren...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "mainnetExplain": "Je zit op het main Ethereum wereldwijde netwerk", + "testnetExplain": "Je bent actief op het __name__, VERSTUUR GEEN echte Ether naar deze adressen", + "privatenetExplain": "Je zit op een private net, VERSTUUR GEEN echte Ether naar deze adressen", + "unknownnetExplain": "Niet in staat om te bepalen op welk netwerk je zit", + "peers": "peers" + }, + "sidebar": { + "buttons": { + "browser": "Verkennen" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "Geen accounts ingesteld", + "connect": "Verbind" + } + }, + "startScreen": { + "runningNodeFound": "Lopende Ethereum node gevonden!", + "startingNode": "Ethereum node starten...", + "stoppingNode": "Ethereum node stoppen...", + "startedNode": "Applicatie starten...", + "nodeConnectionTimeout": "Ethereum node opstarten niet mogelijk!
Als je Geth geinstalleerd hebt, gebruik dan dit commando om het op te starten:
geth --ipcpath __path__

Of meld een fout ", + "nodeBinaryNotFound": "Geen Ethereum node gevonden!
Start er a.u.b. handmatig een. ", + "nodeStarting": "Ethereum node opstarten...", + "nodeStarted": "Ethereum node gestart", + "nodeConnected": "Ethereum node verbonden", + "nodeStopping": "Ethereum node afsluiten...", + "nodeStopped": "Ethereum node gestopt", + "nodeError": "Ethereum node verbindingsfout :'(", + "unableToBindPort": "Ethereum node kan niet opstarten. Draait er al een?", + "nodeSyncing": "Ethereum node moet synchroniseren, even geduld alstublieft...", + "nodeSyncInfo": "Blok __currentBlock__ van __highestBlock__ aan het downloaden.", + "nodeSyncInfoStates": "Blok __displayBlock__ van __highestBlock__ aan het downloaden,
Chain structuur __displayState__ van __displayKnownStates__ aan het downloaden", + "nodeSyncConnecting": "Zoeken naar peers...", + "nodeSyncFoundPeers": "Verbinden met __peers__ peers...", + "peerSearchTimeout": "Sla peer search over", + "launchApp": "Applicatie Opstarten", + "clientBinaries": { + "scanning": "Controleren op node update...", + "downloading": "Downloaden van nieuwe node...", + "loadConfig": "Laden van client config...", + "filtering": "Filteren van client binaries...", + "done": "Ethereum node up-to-date...", + "error": "Fout bij het uitvoeren van de gedownloade binary." + } + }, + "popupWindows": { + "updateAvailable": { + "newVersionAvailable": "Nieuwe __name__ versie beschikbaar", + "version": "Versie", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Updaten en opnieuw opstarten", + "download": "Download nieuwe versie", + "skipUpdate": "Sla update over", + "notNow": "Vraag me later opnieuw", + "checking": "Controleren op updates voor __name__...", + "noUpdateFound": "Geen updates gevonden. Je hebt de laatste versie __name__." + }, + "requestAccount": { + "title": "Account aanmaken", + "enterPassword": "Wachtwoord invoeren", + "repeatPassword": "Wachtwoord herhalen", + "creating": "Account genereren...", + "errors": { + "passwordMismatch": "Je wachtwoorden komen niet overeen.", + "passwordTooShort": "Kies een langer wachtwoord" + } + }, + "unlockMasterPassword": { + "title": "Voer hoofdwachtwoord in", + "enterPassword": "Voer hoofdwachtwoord in", + "unlocking": "Ontgrendelen...", + "errors": { + "wrongPassword": "Wachtwoord is niet correct, probeer het nog eens." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Verzend transactie", + "contractExecution": "Voer contract uit", + "createContract": "Contract aanmaken" + }, + "contractExecutionInfo": "Je staat op het punt een functie uit te voeren op een contract. Dit kan overdrachten van waarde tot gevolg hebben.", + "contractCreationInfo": "Je staat op het punt een contract aan te maken met de gegeven gevevens.", + "enterPassword": "Voer wachtwoord in om de transactie te bevestigen", + "unlocking": "Bevestigen...", + "createContract": "Contract aanmaken", + "estimatedFee": "Ingeschatte transactie kosten", + "estimatedGasError": "De kans is groot dat de transactie zal mislukken. Als je de transactie toch wilt uitvoeren zal misschien alle gas worden verbruikt.", + "transactionThrow": "Het contract staat niet toe dat deze transactie wordt uitgevoerd", + "noEstimate": "We konden de hoeveelheid gas niet inschatten.", + "gasPrice": "Gas prijs", + "perMillionGas": "Ether per millioen gas", + "gasLimit": "Geef maximum transactie kosten aan", + "data": "Ruwe Data", + "parameters": "Parameters", + "buttons": { + "sendTransaction": "Verstuur transactie" + }, + "errors": { + "connectionTimeout": "Kon niet verbinden met de node, is het in de achtergrond uitgevallen?", + "wrongPassword": "Onjuist wachtwoord", + "multipleKeysMatchAddress": "Meerdere keys matchen hebben hetzelfde adres, verwijder duplicaten uit de keystore (menu -> Bestand -> Backup -> Accounts)", + "insufficientFundsForGas": "Onvoldoende saldo in hoofd account (Etherbase) om gas te betalen", + "sameAccount": "Kan niet naar zichzelf versturen" + }, + "showRawBytecode": "Toon ruwe data", + "showDecodedParameters": "Toon gedecodeerde parameters", + "lookupData": "Probeer de data te decoderen", + "lookupDataExplainer": "Zoek hiernaar op het internet", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount." + }, + "onboarding": { + "description": "Ethereum is een decentraal platform voor het bouwen van applicaties op een blockchain: software die immuun is voor fraude en levenslang waarde en eigendom over kan brengen", + "goToTestnet": "Gebruik het test netwerk (Rinkeby)", + "goToTestnetDescription": "Test de technologie vrij in een testongeving, zonder echte Ether te gebruiken.", + "gotoMainnet": "Gebruik hoofdnetwerk", + "gotoMainnetDescription": "Je zult een beetje Ether nodig hebben om contracten uit te voeren. Geen zorgen, we helpen je met het verkrijgen...", + "doYouHaveAWalletFile": "Heb je een wallet bestand?", + "walletFileDescription": "

Als je mee hebt gedaan met de Ethereum voorverkoop van 2014 zou je een bestand met de naam ethereum_wallet_backup.json ontvangen moeten hebben. Je kon dit bestand downloaden na je contributie en is ook per email verstuurd

", + "dropFilesHere": "Sleep voorverkoop bestand hier", + "creating": "Aanmaken...", + "importing": "Importeren...", + "skip": "Sla deze stap over", + "next": "Volgende", + "protectTitle": "Bescherm je account", + "protectDescription": "Kies een wachtwoord voor je nieuwe account. Maak het even veilig alsof het uw huissleutels zijn!", + "accountTitle": "Opladen!", + "accountTitleTestnet": "Mine wat!", + "etherDescription": "Het Ethereum netwerk is gebaseerd op het “Ether” token. Je zal een kleine hoeveelheid nodig hebben om dingen op het netwerk te doen.", + "loadItDescription": "Als je al Bitcoins of een andere cryptocurrency hebt kan je deze makkelijk inwisselen voor Ether met changelly.

Wij raden aan een hoeveelheid van tussen de 0.25 en 1 Ether om te wisselen.", + "mineItDescription": "Op het testnetwerk kun je zelf Ether mijnen door te gaan naar het Ontwikkelaars menu en te kiezen voor Begin Mining.
PROBEER GEEN ECHTE ETHER NAAR DIT ADRES TE VERSTUREN ", + "you": "Je", + "etherbase": "Centrale account (Etherbase)", + "depositBitcoin": "Bitcoin Storten", + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "learnIt": "Leer terwijl je wacht", + "downloadingBlocks": "Blokken downloaden", + "syncMessage": "Blok __displayBlock__ van __highestBlockString__", + "syncMessageWithStates": "Blok __displayBlock__ van __highestBlockString__ (Chain structuur __statesPercent__%)", + "startingSync": "Wachten op synchronisatie..", + "tutorial1Description": "

Het enige wat er nog moet gebeuren is wachten tot de download compleet is. Hier zijn een aantal leessuggesties:

Maak je eigen geld

Maak een cryptocurrency met een vaste uitgeveven hoeveelheid, tokens die vermogen uit de echte wereld voorstellen, etc

", + "tutorial2Description": "

Start een crowdsale

Haal geld op voor een gemeenschappelijk doel, volledig betrouwbaar zonder derde partij. Ga om het traditionele systeem heen en haal geld direct bij de bron op door een organisatie te crowdfunden via de blockchain

", + "tutorial3Description": "

Blockchain Organisatie

Maak een autonome organisatie aan met onbreekbare regels over het uitgeven van geld en wie beslissingen kan maken. Laat je investeerders een actieve rol nemen in het besluiten hoe geld wordt uitgegeven

", + "buttons": { + "showPassword": "Toon wachtwoord", + "importAccount": "Importeer account", + "launchApp": "Start Applicatie!", + "learnReceipt": "Leer dit recept" + }, + "errors": { + "nodeNotStartedYet": "Wacht nog een aantal seconden tot je node volledig is opgestart en probeer het nog een keer", + "unknownFile": "Bestand niet herkent.", + "wrongPassword": "Incorrect wachtwoord.", + "importFailed": "Bestand importeren mislukt: __error__" + } + }, + "connectAccount": { + "chooseAccountTitle": "Kies account", + "createAccount": "Creëer nieuw account", + "pinToSidebar": "Pin app aan de sidebar", + "connectAccountDescription": "Je deelt je indentiteit met __dappName__. Hierdoor heeft de app toegen tot alle openbare informatie van uw accounts inclusief de saldi." + } + } + }, + "elements": { + "checksumAlert": "Dit adres ziet er valide uit, maar het mist een aantal beveiligingsfuncties die je zullen beschermen teken typfouten, dus ga graag even na of dit de goede is. Als aangeveven, ga na of het beveiligingsicoon klopt.", + "identiconHelper": "Dit is een beveilliginsicoon, als er enige veranderingen op dit adres plaats vinden dan zou er een volledig ander icoon moeten staan", + "type": { + "address": "Adres", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.pt.i18n.json b/interface/i18n/mist.pt.i18n.json new file mode 100644 index 0000000..7f93165 --- /dev/null +++ b/interface/i18n/mist.pt.i18n.json @@ -0,0 +1,283 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "Sobre __app__", + "checkForUpdates": "Procurar Atualizações...", + "checkForNodeUpdates": "Check for Ethereum node updates...", + "services": "Serviços", + "hide": "Ocultar o __app__", + "hideOthers": "Ocultar Outros", + "showAll": "Mostrar Todos", + "quit": "Fechar __app__" + }, + "file": { + "label": "Arquivos", + "importPresale": "Importar conta", + "newAccount": "Nova conta", + "backup": "Cópia de segurança", + "backupKeyStore": "Contas", + "backupMist": "Carteiras, contratos e etc", + "swarmUpload": "Subir arquivo para Swarm..." + }, + "edit": { + "label": "Editar", + "undo": "Desfazer", + "redo": "Refazer", + "cut": "Cortar", + "copy": "Copiar", + "paste": "Colar", + "selectAll": "Selecionar tudo" + }, + "view": { + "label": "Ver", + "fullscreen": "Modo de tela cheia", + "default": "Default" + }, + "develop": { + "uploadToSwarm": "Upload no Swarm", + "label": "Desenvolvimento", + "devTools": "Mostrar ferramentas de desenvolvedor", + "devToolsMistUI": "Interface Mist", + "devToolsWalletUI": "Interface Carteira", + "devToolsWebview": "__webview__", + "runTests": "Realizar testes", + "logFiles": "Mostrar arquivos de logs", + "ethereumNode": "Node", + "network": "Rede", + "mainNetwork": "Rede principal", + "startMining": "⛏ Iniciar mineração", + "stopMining": "⛏ Parar mineração", + "externalNode": "using external node", + "openRemix": "Open Remix IDE", + "nodeMode": "Chain download", + "fullNode": "Store full blockchain", + "lightNode": "Use light Node (experimental!)" + }, + "window": { + "label": "Janela", + "minimize": "Minimizar", + "close": "Fechar", + "toFront": "Trazer todas para frente" + }, + "help": { + "label": "Ajuda", + "reportBug": "Report an issue on Github" + } + }, + "errors": { + "nodeConnect": "Não conseguiu se conectar? Veja os logs para saber mais:", + "nodeStartup": "O node não pode ser iniciado. Você já tem um instalado? Ele está fazendo upgrade do banco de dados?", + "timeSync": { + "title": "Seu computador está fora de sincronia!", + "description": "Para sincronizar com a rede Ethereum você precisa que seu computador esteja sincronizado com um servidor de tempo preciso.", + "win32": "Vá em ‘Ajustes de tempo’ depois a aba ‘internet’ nas suas preferências de sistema e marque a opção ‘sincronizar com um servidor de tempo’. Veja esse guia para mais detalhes: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "Para instalar um servidor de tempo, instale \"ntp\" via \"apt-get install ntp\".", + "darwin": "Abra suas preferências, escolha \"preferências de tempo\" e marque \"Ajustar o tempo automaticamente\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in downloaded node!", + "description": "__algorithm__: __hash__\n\nPlease install the __type__ node version __version__ manually." + }, + "legacyChain": { + "title": "Legacy chain detected", + "description": "Your node is currently on the unsupported Ethereum Classic chain. To use this chain use tools provided by the ethereum classic project at\nhttps://ethereumclassic.github.io.\n\nTo revert to the main ethereum chain follow the tutorial here:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Recarregar", + "openDevTools": "Abrir ferramentas de desenvolvimento", + "inspectElements": "Inspecionar elemento" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ blocos restantes", + "blockReceived": "Novo bloco recebido", + "timeSinceBlock": "Tempo corrido desde último bloco", + "blockNumber": "Número de seu bloco atual", + "testnetExplain": "Você está na rede de teste, NÃO ENVIE ethers de verdade para essas contas", + "peers": "nós", + "checkingWhichNetwork": "Checking network...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "mainnetExplain": "You are on the main Ethereum global network", + "privatenetExplain": "You are on a private net, DO NOT SEND any real ether to these addresses", + "unknownnetExplain": "Unable to determine which network you are on" + }, + "sidebar": { + "buttons": { + "browser": "Navegar" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "Sem nenhuma conta", + "connect": "Connect" + } + }, + "startScreen": { + "runningNodeFound": "Node Ethereum encontrado!", + "startingNode": "Iniciando Node...", + "startedNode": "Iniciando aplicativo...", + "nodeConnectionTimeout": "Não pode inicializar um Node!
Instale um manualmente, e use esse comando para executa-lo:
geth --ipcpath __path__

Caso não consiga, entre em contato ", + "nodeBinaryNotFound": "Nó não encontrado!
Instale um manualmente", + "nodeSyncing": "Sincronizando, favor aguarde...", + "nodeSyncInfoStates": "Carregando bloco __displayBlock__ de __highestBlock__,
Lendo estrutura __displayState__ de __displayKnownStates__", + "nodeSyncInfo": "Carregando bloco __displayBlock__ de __highestBlock__.", + "nodeSyncConnecting": "Procurando outros nós...", + "peerSearchTimeout": "Não procure nós agora", + "launchApp": "Iniciar Applicativo", + "stoppingNode": "Stopping Ethereum node...", + "nodeStarting": "Ethereum node starting up...", + "nodeStarted": "Ethereum node started", + "nodeConnected": "Ethereum node connected", + "nodeStopping": "Ethereum node stopping...", + "nodeStopped": "Ethereum node stopped", + "nodeError": "Ethereum node connection error :'(", + "unableToBindPort": "Ethereum node cannot run. Is another instance already running?", + "nodeSyncFoundPeers": "Connecting to __peers__ peers...", + "clientBinaries": { + "scanning": "Checking for node update...", + "downloading": "Downloading new node...", + "loadConfig": "Loading client config...", + "filtering": "Filtering client binaries...", + "done": "Ethereum node up-to-date...", + "error": "Error running downloaded binary." + } + }, + "popupWindows": { + "requestAccount": { + "title": "Criar conta", + "enterPassword": "Digite sua senha", + "repeatPassword": "Digite a senha novamente", + "creating": "Criando conta...", + "errors": { + "passwordMismatch": "Senhas não batem.", + "passwordTooShort": "Make a longer password" + } + }, + "unlockMasterPassword": { + "title": "Coloque a chave-mestra", + "enterPassword": "Coloque a chave-mestra", + "unlocking": "Abrindo...", + "errors": { + "wrongPassword": "Senha incorreta, tente novamente." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Enviar transação", + "contractExecution": "Executar ordem", + "createContract": "Criar contrato" + }, + "contractExecutionInfo": "Você irá executar uma ordem em um contrato. Isso pode envolver transferência de valores.", + "contractCreationInfo": "Você irá criar um contrato", + "enterPassword": "Digite a senha para confirmar", + "unlocking": "Confirmando...", + "createContract": "Criar contrato", + "estimatedFee": "Taxa estimada", + "estimatedGasError": "Transação inválida, se executada irá gastar todo o combustível dado.", + "gasPrice": "Preço do combustível", + "perMillionGas": "ether por milhão de combustível", + "gasLimit": "Providenciar taxa máxima", + "data": "Dados", + "buttons": { + "sendTransaction": "Enviar transação" + }, + "errors": { + "connectionTimeout": "Não pode se conectar com Node, é possível que tenha sido interrompido pelo sistema", + "wrongPassword": "Senha errada", + "multipleKeysMatchAddress": "Multiple keys match address. Please remove duplicates from keystore (Arquivos -> Cópia de segurança -> Contas)", + "insufficientFundsForGas": "Insufficient funds in main account (etherbase) to pay for gas", + "sameAccount": "Can't send to itself" + }, + "transactionThrow": "The contract won't allow this transaction to be executed", + "noEstimate": "We couldn't estimate the gas.", + "parameters": "Parameters", + "showRawBytecode": "show raw data", + "showDecodedParameters": "show decoded parameters", + "lookupData": "Try to decode data", + "lookupDataExplainer": "Look this up on the internet", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount." + }, + "onboarding": { + "description": "Ethereum é uma plataforma decentralizada para construir aplicativos no blockchain: apps a prova de fraude, censura ou corrupção que podem transferir valor e títulos de propriedade", + "goToTestnet": "Usar a rede de teste (Rinkeby)", + "goToTestnetDescription": "Experimente a tecnologia usando uma rede de teste sem valores reais.", + "gotoMainnet": "Usar a rede Ethereum principal", + "gotoMainnetDescription": "Você irá precisar de ether para executar contratos. Não se preocupe, iremos lhe ajudar com isso", + "doYouHaveAWalletFile": "Você tem um arquivo de conta?", + "walletFileDescription": "

Se você participou da pré-venda de ether em 2014, você deve ter um arquivo chamado ethereum_wallet_backup.json. Além de fazer o download, esse arquivo também foi enviado para o seu email na época

", + "dropFilesHere": "Largar arquivo de pré-venda", + "creating": "Criando...", + "importing": "Importando...", + "skip": "Pule esse passo", + "next": "Próximo", + "protectTitle": "Proteja sua conta", + "protectDescription": "Crie uma senha para sua conta nova. Escolha uma senha forte como se fosse guardar a porta da sua casa", + "accountTitle": "Adicione crédito", + "accountTitleTestnet": "Faça mineração", + "etherDescription": "A rede Ethereum usa ether como uma unidade de troca entre criadores e processadores de contratos. Você não precisa obter uma quantidade muito grande de ether para poder realizar funções na rede.", + "loadItDescription": "Se você já tem Bitcoin ou outra criptomoeda, a forma mais simples de convertê-la é usando changelly.

Recomendamos carregar algo como 0.25 a 1 ether.", + "mineItDescription": "Na rede de teste é possível minerar ether escolhendo o menu Desenvolvimento e depois Iniciar mineração.
NÃO ENVIE ETHER DE VERDADE PARA ESSE ENDEREÇO ", + "you": "VOCÊ", + "etherbase": "Conta principal (etherbase)", + "depositBitcoin": "Depositar Bitcoin", + "learnIt": "Leia enquanto você aguarda", + "downloadingBlocks": "Baixando blocos", + "tutorial1Description": "

Agora basta esperar que o download seja concluído. Aqui está uma sugestão de leitura:

Faça seu próprio dinheiro

Crie uma criptomoeda com limite fixo, emita fichas que representam ativos no mundo físico, etc

", + "tutorial2Description": "

Começe um financiamento coletivo

Faça uma vaquinha para um objetivo comunitário, sem risco de fraudes. Levante fundos diretamente pela internet, sem intermediários

", + "tutorial3Description": "

Crie uma organização no Blockchain

Crie uma entidade autônima com regras invioláveis de como seus fundos podem ser gastos e quem pode tomar decisões. Permita que os seus financiadores tenham decisões diretas sobre em que os recursos da organização serão usados

", + "buttons": { + "showPassword": "Mostrar senha", + "importAccount": "Importar conta", + "launchApp": "Iniciar aplicativo!", + "learnReceipt": "Aprenda a fazer isso!" + }, + "errors": { + "nodeNotStartedYet": "Espere alguns segundos e tente novamente", + "unknownFile": "Arquivo não reconhecido.", + "wrongPassword": "Senha incorreta.", + "importFailed": "Não pode importar. Erro: __error__" + }, + "buyEther": "Comprar Ether", + "viaChangelly": "Aceita cartão e cryptomoedas através de Changelly", + "syncMessage": "Block __displayBlock__ of __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ of __highestBlockString__ (Chain structure __statesPercent__%)", + "startingSync": "Getting ready to sync.." + }, + "updateAvailable": { + "newVersionAvailable": "New __name__ version available", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Update and Restart", + "download": "Download new version", + "skipUpdate": "Skip Update", + "notNow": "Ask me later", + "checking": "Checking for updates to __name__...", + "noUpdateFound": "No update found. You are running the latest version of __name__." + }, + "connectAccount": { + "chooseAccountTitle": "Choose account", + "createAccount": "Create new account", + "pinToSidebar": "Pin app to the sidebar", + "connectAccountDescription": "You are sharing your identity with __dappName__. This allows the app to see any public information of your accounts, including balances connected to it." + } + } + }, + "elements": { + "checksumAlert": "Esse endereço parece válido, mas não tem algumas características de segurança contra errors de digitação acidental, então assegure-se que é o recipiente correto. Se possível, confira o ícone de segurança.", + "identiconHelper": "Esse é um ícone de segurança. Se houver qualquer mudança no endereço, ele deve ter uma aparência completamente diferente", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.ru.i18n.json b/interface/i18n/mist.ru.i18n.json new file mode 100644 index 0000000..7cc90b0 --- /dev/null +++ b/interface/i18n/mist.ru.i18n.json @@ -0,0 +1,281 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "О __app__", + "checkForUpdates": "Проверить обновления...", + "checkForNodeUpdates": "Check for Ethereum node updates...", + "services": "Сервисы", + "hide": "Скрыть __app__", + "hideOthers": "Скрыть прочие", + "showAll": "Показать все", + "quit": "Выйти из __app__" + }, + "edit": { + "label": "Редактировать", + "undo": "Отменить", + "redo": "Повторить", + "cut": "Вырезать", + "copy": "Копировать", + "paste": "Вставить", + "selectAll": "Выделить все" + }, + "view": { + "label": "Вид", + "fullscreen": "Полноэкранный режим", + "default": "По умолчанию" + }, + "file": { + "label": "Аккаунты", + "importPresale": "Импорт аккаунтов", + "newAccount": "Создать аккаунт", + "backup": "Резервное копирование", + "backupKeyStore": "Аккаунтов", + "backupMist": "Данных приложения" + }, + "develop": { + "uploadToSwarm": "Загрузить в Swarm", + "label": "Дополнительно", + "devTools": "Выбрать инструмент разработчика", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Wallet UI", + "devToolsWebview": "__webview__", + "runTests": "Запустить тесты", + "logFiles": "Показать журнал", + "ethereumNode": "Ethereum-нода", + "network": "Сеть", + "mainNetwork": "Основная сеть", + "startMining": "⛏ Запустить майнинг", + "stopMining": "⛏ Остановить майнинг", + "externalNode": "using external node", + "openRemix": "Open Remix IDE", + "nodeMode": "Chain download", + "fullNode": "Store full blockchain", + "lightNode": "Use light Node (experimental!)" + }, + "window": { + "label": "Окно", + "minimize": "Свернуть", + "close": "Закрыть", + "toFront": "Все окна на переднем плане" + }, + "help": { + "label": "Помощь", + "reportBug": "Report an issue on Github" + } + }, + "errors": { + "nodeConnect": "Не удается подключиться к ноде? Ищите подробности в журнале:", + "nodeStartup": "Похоже, что нода не может быть запущена, может у вас уже есть запущенная нода? Или, возможно, сейчас запущено обновление базы данных?", + "timeSync": { + "title": "Часы на вашем компьютере не синхронизированы.", + "description": "Для успешной синхронизации с сетью Ethereum вам необходимо синхронизировать часы вашего компьютера с текущим временем на сервере.", + "win32": "Откройте системные настройки \"Дата и время\" и установите флажок для настройки времени по Интернету. Смотрите подробности в этом описании: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "Чтобы использовать сервер синхронизации времени установите \"ntp\" через команду \"apt-get install ntp\".", + "darwin": "Для включения синхронизации времени откройте системные настройки и укажите: \"Устанавливать время и дату автоматически\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in downloaded node!", + "description": "__algorithm__: __hash__\n\nPlease install the __type__ node version __version__ manually." + }, + "legacyChain": { + "title": "Legacy chain detected", + "description": "Your node is currently on the unsupported Ethereum Classic chain. To use this chain use tools provided by the ethereum classic project at\nhttps://ethereumclassic.github.io.\n\nTo revert to the main ethereum chain follow the tutorial here:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Перезагрузить", + "openDevTools": "Открыть инструменты разработчика", + "inspectElements": "Исследовать элемент" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ блоков не загружено", + "blockReceived": "Получен новый блок", + "blockNumber": "Номер вашего последнего блока", + "timeSinceBlock": "Прошедшее время ожидания нового блока", + "checkingWhichNetwork": "Проверка сети...", + "mainNetwork": "Основная сеть", + "testNetwork": "Тестовая сеть", + "privateNetwork": "Приватная сеть", + "mainnetExplain": "Вы подключены к основной Ethereum-сети", + "testnetExplain": "Вы подключены к тестовой Ethereum-сети, НЕ ОТПРАВЛЯЙТЕ настоящий эфир на эти адреса", + "privatenetExplain": "Вы подключены к приватной Ethereum-сети, НЕ ОТПРАВЛЯЙТЕ настоящий эфир на эти адреса", + "unknownnetExplain": "Не удается определить текущую подключенную сеть", + "peers": "peers" + }, + "sidebar": { + "buttons": { + "browser": "Посмотреть" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "Аккаунт не установлен", + "connect": "Connect" + } + }, + "startScreen": { + "runningNodeFound": "Обнаружена запущеная Ethereum-нода!", + "startingNode": "Запуск Ethereum-ноды...", + "stoppingNode": "Остановка Ethereum-ноды...", + "startedNode": "Запуск приложения...", + "nodeConnectionTimeout": "Не удалось запустить Ethereum-ноду!
Если вы установили Geth, используйте следующую команду для запуска:
geth --ipcpath __path__

Либо сообщите от проблеме ", + "nodeBinaryNotFound": "Не найдены программные файлы для Ethereum-ноды!
Пожалуйста, для начала изучите руководство. ", + "nodeStarting": "Ethereum-нода запускается...", + "nodeStarted": "Ethereum-нода запущена", + "nodeConnected": "Ethereum-нода подключена", + "nodeStopping": "Ethereum-нода останавливается...", + "nodeStopped": "Ethereum-нода остановлена", + "nodeError": "Ошибка подключения к Ethereum-ноде :'(", + "unableToBindPort": "Ethereum-нода не запущена. Может запущен другой экземпляр?", + "nodeSyncing": "Ethereum-ноде необходимо синхронизироваться, пожалуйста подождите...", + "nodeSyncInfo": "Загружено блоков __displayBlock__ из __highestBlock__", + "nodeSyncInfoStates": "Загружено блоков __displayBlock__ из __highestBlock__,
Загружено частей структуры блокчейна __displayState__ из __displayKnownStates__", + "nodeSyncConnecting": "Поиск пиров...", + "nodeSyncFoundPeers": "Количество подключеных пиров __peers__...", + "peerSearchTimeout": "Пропустить поиск пиров", + "launchApp": "Запуск приложения", + "clientBinaries": { + "scanning": "Checking for node update...", + "downloading": "Downloading new node...", + "loadConfig": "Loading client config...", + "filtering": "Filtering client binaries...", + "done": "Ethereum node up-to-date...", + "error": "Error running downloaded binary." + } + }, + "popupWindows": { + "updateAvailable": { + "newVersionAvailable": "New __name__ version available", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Update and Restart", + "download": "Download new version", + "skipUpdate": "Skip Update", + "notNow": "Ask me later", + "checking": "Checking for updates to __name__...", + "noUpdateFound": "No update found. You are running the latest version of __name__." + }, + "unlockMasterPassword": { + "title": "Ввод мастер-пароля", + "enterPassword": "Введите мастер-пароль", + "unlocking": "Разблокировка...", + "errors": { + "wrongPassword": "Неверный пароль, попробуйте еще раз." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Отправить транзакцию", + "contractExecution": "Выполнить контракт", + "createContract": "Создать контракт" + }, + "contractExecutionInfo": "Вы собираетесь выполнить часть контракта. Этот процесс может включать передачу значений (транзакцию).", + "contractCreationInfo": "Вы собираетесь создать контракт на основе предоставленных данных.", + "enterPassword": "Введите пароль для подтверждения транзакции", + "unlocking": "Подтвержение...", + "createContract": "Создание контракта", + "estimatedFee": "Расчетная сумма вознаграждения", + "estimatedGasError": "Задание не может быть выполнено, так как будет израсходован весь выделенный газ", + "gasPrice": "Цена газа", + "perMillionGas": "эфир за миллион газа", + "gasLimit": "Установить максимальную сумму вознаграждения", + "data": "Данные", + "buttons": { + "sendTransaction": "Отправить транзакцию" + }, + "errors": { + "connectionTimeout": "Не удается подключиться к ноде, возможно завершилось фоновое приложение?", + "wrongPassword": "Неверный пароль", + "multipleKeysMatchAddress": "У нескольких ключей совпадает адрес, удалите дубликаты из хранилища ключей (Меню -> Аккаунты -> Резервное копирование -> Аккаунтов)", + "insufficientFundsForGas": "Недостаточно средств на основном счете (ETHERBASE) чтобы заплатить за газ", + "sameAccount": "Can't send to itself" + }, + "transactionThrow": "The contract won't allow this transaction to be executed", + "noEstimate": "We couldn't estimate the gas.", + "parameters": "Parameters", + "showRawBytecode": "show raw data", + "showDecodedParameters": "show decoded parameters", + "lookupData": "Try to decode data", + "lookupDataExplainer": "Look this up on the internet", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount." + }, + "onboarding": { + "description": "Etherium представляет собой децентрализованную платформу основанную на блокчейне для создания надежных и децентрализованных приложений", + "goToTestnet": "Использовать тестовую сеть (Rinkeby)", + "goToTestnetDescription": "Свободное тестирование технологии в тестовой сети (sandbox), без использования реального эфира.", + "gotoMainnet": "Использовать основную сеть", + "gotoMainnetDescription": "Вам потребуется некоторое количество эфира для того, чтобы создавать и выполнять контракты. Не волнуйтесь, мы вам поможем получить некоторое количество...", + "doYouHaveAWalletFile": "У вас есть файл кошелька?", + "walletFileDescription": "

Если вы участвовали в Ethereum Pre-sale 2014, у вас должен быть файл с именем ethereum_wallet_backup.json. Он был загружен после продажи, а также отправлен на электронную почту

", + "dropFilesHere": "Перетащите сюда ваш файл", + "creating": "Создание...", + "importing": "Импорт...", + "skip": "Пропустить этот шаг", + "next": "Далее", + "protectTitle": "Защитите ваш аккаунт", + "protectDescription": "Выберите пароль для новой учетной записи. Придумайте такой пароль, как будто он защитит ваши ключи от дома!", + "accountTitle": "Загрузите его!", + "etherDescription": "Сеть Ethereum основана на маркерах называемых “Ether” (Эфир). Он вам необходим в небольшом количетсве для того, что бы что-либо сделать в сети Etherium.", + "loadItDescription": "Если у вас уже есть Bitcoin, или любая другая криптовалюта, вы можете легко преобразовать её в эфир (Ether) с помощью changelly.

Мы рекомендуем загрузить где-то от 0.25 до 1 эфира.", + "mineItDescription": "В тестовой сети вы можете добыть (намайнить) эфир сами, перейдя в меню Дополнительно и выбрав Запустить майнинг.
НЕ ПЫТАЙТЕСЬ ОТПРАВИТЬ РЕАЛЬНЫЙ ЭФИР НА ЭТОТ АДРЕС", + "you": "ВЫ", + "etherbase": "Основной аккаунт (etherbase)", + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "learnIt": "Изучайте, пока ожидаете", + "downloadingBlocks": "Загрузка блоков", + "syncMessage": "Блок __displayBlock__ из __highestBlockString__", + "syncMessageWithStates": "Блок __displayBlock__ из __highestBlockString__ (Структура блокчейна __statesPercent__%)", + "tutorial1Description": "

Теперь ожидайте окончания загрузки для завершения. Вот несколько советов:

Сделайте свои собственные деньги

Сделайте криптовалюту с запасом фиксированного рынка, маркеры представляющие реальные мировые активы и т.д.

", + "tutorial2Description": "

Организуйте crowdsale

Привлечение средств для достижения общей цели полностью надёжно только без участия третьей стороны. Обойдите барьер традиционной системы финансирования и перейдите к финансированию организации непосредственно через блокчейн.

", + "tutorial3Description": "

Создайте организацию

Создайте автономную организацию с правилами о расходовании денег и принятии решений для вас и ваших инвесторов.

", + "buttons": { + "showPassword": "Показать пароль", + "importAccount": "Импортировать аккаунт", + "launchApp": "Запустить приложение!", + "learnReceipt": "Узнать этот рецепт" + }, + "errors": { + "nodeNotStartedYet": "Подождите несколько секунд, пока ваша нода не будет полностью запущена и повторите попытку.", + "unknownFile": "Файл не распознается.", + "wrongPassword": "Неверный пароль.", + "importFailed": "Не удалось импортировать файл, дополнительно: __error__" + }, + "accountTitleTestnet": "Mine some!", + "startingSync": "Getting ready to sync.." + }, + "connectAccount": { + "chooseAccountTitle": "Choose account", + "createAccount": "Create new account", + "pinToSidebar": "Pin app to the sidebar", + "connectAccountDescription": "You are sharing your identity with __dappName__. This allows the app to see any public information of your accounts, including balances connected to it." + }, + "requestAccount": { + "title": "Create account", + "enterPassword": "Enter password", + "repeatPassword": "Repeat password", + "creating": "Generating account...", + "errors": { + "passwordMismatch": "Your passwords don't match.", + "passwordTooShort": "Make a longer password" + } + } + } + }, + "elements": { + "checksumAlert": "Этот адрес выглядит правильно, но не хватает некоторых функций безопасности, которые могут защитить от опечаток. Поэтому, пожалуйста, дважды проверяйте введеный адрес. Если у вас есть возможность, пожалуйста, проверьте также соответствие иконки безопасности.", + "identiconHelper": "Это значок безопасности, если будут какие-либо изменения в адресе получателя - иконка будет совершенно другая", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.sq.i18n.json b/interface/i18n/mist.sq.i18n.json new file mode 100644 index 0000000..145a982 --- /dev/null +++ b/interface/i18n/mist.sq.i18n.json @@ -0,0 +1,290 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "Rreth __app__", + "checkForUpdates": "Kërko për përditësime...", + "checkForNodeUpdates": "Kërko për përditësime të nyjes Ethereum...", + "services": "Shërbime", + "hide": "Fshih __app__", + "hideOthers": "Fshih të tjerat", + "showAll": "Shfaq të gjitha", + "quit": "Dil nga __app__" + }, + "file": { + "label": "Skedari", + "importPresale": "Merr llogari", + "newAccount": "Llogari e re", + "backup": "Ruaj kopje rezervë", + "backupKeyStore": "Llogari", + "backupMist": "Të Dhënat e Aplikimit", + "swarmUpload": "Ngarko në Swarm..." + }, + "edit": { + "label": "Redakto", + "undo": "Zhbëj", + "redo": "Ribëj", + "cut": "Pri", + "copy": "Kopjo", + "paste": "Ngjit", + "selectAll": "Përzgjidh të gjitha" + }, + "view": { + "label": "Shiko", + "fullscreen": "Kalo me ekran të plotë", + "default": "Vlera e parazgjedhur" + }, + "develop": { + "label": "Zhvillo", + "devTools": "Shfaq mjetet e zhvillimit", + "devToolsMistUI": "Mist UI", + "devToolsWalletUI": "Kuletë UI", + "devToolsWebview": "__webview__", + "runTests": "Fillo testimet", + "logFiles": "Trego skedarin me të dhënat e regjistruara", + "openRemix": "Hap IDE-në Remix", + "externalNode": "duke përdorur nyje të jashtme", + "ethereumNode": "Nyje Ethereum", + "network": "Rrjet", + "mainNetwork": "Rrjeti kryesor", + "nodeMode": "Shkarkim zinxhir", + "fullNode": "Ruaj zinxhirin e plotë të blloqeve", + "lightNode": "Përdor nyje të lehtë (eksperimentale!)", + "startMining": "⛏ Fillo të Prodhosh", + "stopMining": "⛏ Ndalo së Prodhuari" + }, + "window": { + "label": "Dritare", + "minimize": "Minimizo", + "close": "Mbyll", + "toFront": "Sill Gjithçka në Pamje të Parë" + }, + "help": { + "label": "Ndihmë", + "discord": "Discord", + "reddit": "Reddit", + "reportBug": "Raportoni një problem në Github" + } + }, + "errors": { + "nodeConnect": "Nuk mund të lidhesh me nyje? Shiko të dhënat e regjistruara për më shumë:", + "nodeStartup": "Duket se nyja nuk mund të niset. Mos keni ndonjë nyje tjetër është aktive? Mos është duke pasuruar bazën e të dhënave në këto momente?", + "timeSync": { + "title": "Ora e kompjuterit tuaj nuk është e sinkronizuar.", + "description": "Në mënyrë që të sinkronizoheni me sukses me rrjetin Ethereum ju duhet të sinkronizoni orën tuaj të kompjuterit me një server sinkronizues kohe.", + "win32": "Shkoni në \"Internet Time Settings\" te preferencat tuaja të sistemit dhe përzgjidhni opsionin përkatës. Për detaje shikoni këtë udhëzues: http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "Që të fusni në punë një server kohe të sinkronizuar instaloni \"ntp\" nëpërmjet \"apt-get install ntp\".", + "darwin": "Që të mundësoni një sinkronizim kohe, hapni preferencat e kohës dhe përzgjidhni \"Set the time and date automatically\"." + }, + "nodeChecksumMismatch": { + "title": "Konflikt skedarësh në nyjen e shkarkuar!", + "description": "__algorithm__: __hash__\n\nJu lutemi të instaloni versionin node __type__ __version__ manualisht." + }, + "legacyChain": { + "title": "U zbulua zinxhir i vjetër", + "description": "Nyja juaj ndodhet në zinxhirin e pasuportuar Ethereum Classic. Për të përdorur këtë zinxhir, përdorni mjetet e mundësuara nga projekti Ethereum Classic në\nhttps://ethereumclassic.github.io.\n\nPër të kaluar në zinxhirin kryesor Ethereum ndiqni udhëzuesin këtu:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "Ringarko", + "openDevTools": "Hap Mjetet e Zhvilluesit", + "inspectElements": "Inspekto Elemente" + }, + "nodeInfo": { + "nodeSyncing": "__blockDiff__ blloqe të mbetura", + "blockReceived": "U mor një bllok i ri", + "blockNumber": "Numri i bllokut tuaj të fundit", + "timeSinceBlock": "Koha e kaluar që nga blloku i fundit", + "checkingWhichNetwork": "Duke kontrolluar rrjetin...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "testnetExplain": "Jeni në një rrjet testimi, MOS DËRGONI asnjë ether të vërtetë në këto adresa", + "mainnetExplain": "Jeni në rrjetin kryesor global Ethereum", + "privatenetExplain": "Jeni në një rrjet privat, MOS DËRGONI asnjë ether të vërtetë në këto adresa", + "unknownnetExplain": "Nuk mund të vlerësohet rrjeti ku ndodheni tani", + "peers": "miq" + }, + "sidebar": { + "buttons": { + "browser": "Shfleto" + }, + "submenu": { + "account": "Llogaria", + "account_plural": "Llogaritë", + "connectAccounts": "Lidh Llogari" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "Nuk ka llogari të krijuar", + "connect": "Lidhu" + } + }, + "startScreen": { + "runningNodeFound": "U gjet nyje Ethereum në punë!", + "startingNode": "Duke krijuar nyje Ethereum...", + "startedNode": "Duke nisur aplikacionin...", + "nodeConnectionTimeout": "Nuk mund të niset nyje Ethereum!
Nëse ju instaluat Geth, përdorni këtë komandë ta krijoni:
geth --ipcpath __path__

Ose raportoni një problem ", + "nodeBinaryNotFound": "Nuk u gjet nyje binare Ethereum!
Ju lutemi krijoni një manualisht më parë. ", + "nodeStarting": "Nyja Ethereum po niset...", + "nodeStarted": "Nyja Ethereum u nis", + "nodeConnected": "Nyja Ethereum u lidh", + "nodeStopping": "Nyja Ethereum po ndalon...", + "nodeStopped": "Nyja Ethereum ndaloi", + "nodeError": "Problem lidhjeje i nyjes Ethereum:'(", + "unableToBindPort": "Nyja Ethereum nuk munt të fillojë. Mos ka ndonjë instancë tjetër të nisur?", + "nodeSyncing": "Nyja Ethereum ka nevojë të sinkronizohet, ju lutemi prisni...", + "nodeSyncInfo": "Duke marrë bllokun __currentBlock__ nga __highestBlock__.", + "nodeSyncInfoStates": "Duke shkarkuar bllokun __displayBlock__ nga __highestBlock__,
Duke shkarkuar strukturën e zinxhirit __displayState__ nga __displayKnownStates__", + "nodeSyncConnecting": "Duke kërkuar miq...", + "stoppingNode": "Duke ndaluar nyjen Ethereum...", + "nodeSyncFoundPeers": "Duke u lidhur me __peers__ miq...", + "peerSearchTimeout": "Kapërce kërkimin e miqve", + "launchApp": "Hap Aplikacionin", + "clientBinaries": { + "scanning": "Duke kërkuar për përditësime të nyjes...", + "downloading": "Duke shkarkuar nyje të re...", + "loadConfig": "Duke ngarkuar konfigurimin e klientit...", + "filtering": "Duke filtruar skedarët binarë të klientit...", + "done": "Nyja Ethereum e përditësuar...", + "error": "Problem me ekzekutimin e programit të shkarkuar." + } + }, + "popupWindows": { + "updateAvailable": { + "newVersionAvailable": "Version i ri i __name__ i përdorshëm", + "version": "Versioni", + "downloadURL": "URL e shkarkimit", + "checksum": "Checksum", + "downloadAndRestart": "Përditëso dhe Rindiz", + "download": "Shkarko version të ri", + "skipUpdate": "Kapërce përditësim", + "notNow": "Më pyet më vonë", + "checking": "Duke kontrolluar për përditësime të __name__...", + "noUpdateFound": "Nuk u gjetën përditësime. Po përdorni versionin më të fundit të __name__." + }, + "requestAccount": { + "title": "Krijoni llogari", + "enterPassword": "Fusni fjalëkalimin", + "repeatPassword": "Përsërisni fjalëkalimin", + "creating": "Duke krijuar llogari...", + "backupHint": "Sigurohuni të ruani edhe fjalëkalimin, edhe skedarët çelës!\n\nMund t'i gjeni këta skedarë duke përdorur menunë kryesore -> Skedari -> Ruaj kopje rezervë -> Llogaritë. Ruani një kopje të dosjes \"keystore\" në një vend të sigurt!", + "errors": { + "passwordMismatch": "Fjalëkalimet nuk përputhen.", + "passwordTooShort": "Krijoni një fjalëkalim më të gjatë" + } + }, + "unlockMasterPassword": { + "title": "Fusni fjalëkalimin kryesor", + "enterPassword": "Fusni fjalëkalimin kryesor", + "unlocking": "Duke hapur...", + "errors": { + "wrongPassword": "Fjalëkalimi është i gabuar. Provoni përsëri." + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "Dërgoni transaksionin", + "contractExecution": "Kryeni kontratën.", + "createContract": "Krijoni kontratë" + }, + "contractExecutionInfo": "Ju jeni pranë ekzekutimit të një funksioni në një kontratë. Kjo mund të përfshijë transferim valutash.", + "contractCreationInfo": "Ju jeni pranë krijimit të një kontrate nga të dhënat e marra.", + "enterPassword": "Fusni fjalëkalimin që të konfirmoni transaksionin", + "unlocking": "Duke konfirmuar...", + "createContract": "Krijoni kontratë", + "estimatedFee": "Tarifa e hamendësuar për t'u konsumuar", + "estimatedGasError": "Të dhënat nuk mund të ekzekutohen kështu që do të përdoret i gjithë karburanti.", + "transactionThrow": "Kontrata nuk lejon kryerjen e këtij transaksioni", + "overBlockGasLimit": "Karburanti i kërkuar për kryerjen e këtij veprimi mund ta kalojë limitin e karburantit të bllokut.", + "notEnoughGas": "Mund të mos ketë mjaftueshëm karburant për të përfunduar këtë transaksion me sukses.
Klikoni këtu për të rritur sasinë e karburantit.", + "noEstimate": "Nuk mund të hamendësonim sasinë e nevojshme të karburantit.", + "gasPrice": "Çmimi i karburantit", + "perMillionGas": "ether për milion karburant", + "gasLimit": "Vendos tarifë maksimale", + "data": "Të dhëna të paformatuara", + "parameters": "Parametra", + "buttons": { + "sendTransaction": "Kryej transaksionin" + }, + "errors": { + "connectionTimeout": "Nuk mund të lidhet me nyjen. Mos ka probleme diku?", + "wrongPassword": "Fjalëkalim i gabuar", + "multipleKeysMatchAddress": "Disa çelësa i përshtaten kësaj adrese; ju lutemi hiqni kopjet e dyfishta nga mbajtësja e çelësave (menunë -> Skedari -> Ruaj kopje rezervë -> Llogari)", + "insufficientFundsForGas": "Fonde të pamjaftueshme në adresën kryesore (etherbase) për të paguar për karburant", + "sameAccount": "Nuk mund t'i dërgohet vetes" + }, + "showRawBytecode": "shfaq të dhënat e paformatuara", + "showDecodedParameters": "shfaq parametrat e dekoduar", + "lookupData": "Përpiqu të dekodosh të dhëna", + "lookupDataExplainer": "Kërkojeni në internet" + }, + "onboarding": { + "description": "Ethereum është një platformë e decentralizuar për ndërtim aplikacionesh në një zinxhir blloqesh (blockchain) me gjuhën e vet të programimit", + "goToTestnet": "Përdor rrjetin testues (Rinkeby)", + "goToTestnetDescription": "Testo lirshëm teknologjinë në një rrjet test pa përdorur ether të vërtetë.", + "gotoMainnet": "Përdor rrjetin kryesor", + "gotoMainnetDescription": " Ju do të keni nevojë për pak Ether në mënyrë që të krijoni dhe zbatoni kontrata. Mos u shqetësoni, ne do ju ndihmojmë që të gjeni sa duhet...", + "doYouHaveAWalletFile": "A keni një skedë kulete?", + "walletFileDescription": "

Nëse ju keni marrë pjesë në Parashitjen e Ethereumit 2014, ju duhet të keni një skedë të emëruar ethereum_wallet_backup.json. Eshtë shkarkuar pas shitjes dhe dërguar në emailin tuaj

", + "dropFilesHere": "Vendos skedën e parashitjes", + "creating": "Duke krijuar...", + "importing": "Duke marrë...", + "skip": "Kapërce këtë hap", + "next": "Më tej", + "protectTitle": "Ruaj adresën", + "protectDescription": "Zgjidhni një fjalëkalim për adresën tuaj të re. Krijojeni aq të fortë sa të mjaftonte për të ruajtur çelësat e shtëpisë!", + "accountTitle": "Ngarko", + "accountTitleTestnet": "Puno", + "etherDescription": "Rrjeti Ethereum bazohet në monedhën e quajtur “Ether”. Nevojitet një sasi e vogël e tij për të bërë ndonjë gjë në rrjetin Ethereum.", + "loadItDescription": "Nëse keni Bitcoin ose ndonjë kriptovalutë tjetër, mund t'i këmbeni me ether duke përdorur changelly.

Ne ju rekomandojmë ngarkimin e 0.25 deri 1 ether.", + "mineItDescription": "Në rrjetin test mund të përftoni ether duke shkuar në menunë Zhvillo dhe duke zgjedhur Fillo të punosh.
MOS PROVONI Txxx DxxxRGONI ETHER Txxx VxxxRTETxxx Nxxx KxxxTxxx ADRESxxx ", + "you": "JU", + "etherbase": "Adresa kryesore (etherbase)", + "depositBitcoin": "Depozito Bitcoin", + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "learnIt": "Mësoni ndërkohë që prisni", + "downloadingBlocks": "Duke shkarkuar blloqe", + "syncMessage": "Blloku __displayBlock__ nga __highestBlockString__", + "syncMessageWithStates": "Blloku __displayBlock__ nga __highestBlockString__ (Struktura e zinxhirit __statesPercent__%)", + "startingSync": "Duke u përgatitur për sinkronizim...", + "tutorial1Description": "

Tani mbetet vetëm të prisni sa tv përfundojë shkarkimi. Ja disa sugjerime për lexim:

Krijoni paranë tuaj

Krijoni një kriptovalutë me ofertë fikse tregu, valuta që përfaqësojnë asete të jetës së vërtetë, etj.

", + "tutorial2Description": "

Krijoni \"crowdsales\"

Mblidhni fonde për një qëllim të përbashkët, plotësisht të besueshme pa palë të treta. Kapërceni pengesat e sistemeve tradicionale të mbledhjes së fondeve dhe shkoni drejt e te burimi duke financuar organizatën nëpërmjet zinxhirit të blloqeve.

", + "tutorial3Description": "

Organizatë Blockchain

Krijoni një organizatë autonome me rregulla të pathyeshme mbi shpenzimin e parave dhe marrjen e vendimeve. Lejoni mbështetësit të kenë rol aktivmbi shpenzimin e parave

", + "buttons": { + "showPassword": "Shfaq fjalëkalimin", + "importAccount": "Merr llogari", + "launchApp": "Nis Aplikacionin", + "learnReceipt": "Mëso këtë recetë" + }, + "errors": { + "nodeNotStartedYet": "Prisni edhe disa sekonda derisa nyja të jetë nisur plotësisht dhe provojeni përsëri dhe provojeni përsëri", + "unknownFile": "Skedari nuk njihet.", + "wrongPassword": "Fjalëkalim i gabuar.", + "importFailed": "Skedari nuk mund të merret: __error__" + } + }, + "connectAccount": { + "chooseAccountTitle": "Zgjidhni llogarinë", + "createAccount": "Krijoni llogari të re", + "pinToSidebar": "Vendosni aplikacionin në shiritin anësor", + "connectAccountDescription": "Po shpërndani identitetin tuaj me __dappName__. Kjo i lejon aplikacionit të shohë çdo informacion publik të llogarive tuaja, duke përfshirë vlerat e lidhura me të." + } + } + }, + "elements": { + "checksumAlert": "Kjo adresë duket e vlefshme, por nuk ka disa masa sigurie që ju mbrojnë nga gabimet e shtypjes, kështu që duhet të siguroheni që kjo është adresa e duhur. Nëse e keni, kontrolloni nëse ikona e sigurisë përputhet.", + "identiconHelper": "Kjo është një ikonë sigurie; nëse ka ndonjë ndryshim në adresë ikona e përftuar do të ishte krejt tjetër", + "type": { + "address": "Adresa", + "bool": "Buleane", + "int": "Numër i plotë", + "uint": "Numër Natyror", + "string": "String", + "bytes": "Bajt" + } + } +} diff --git a/interface/i18n/mist.zh-TW.i18n.json b/interface/i18n/mist.zh-TW.i18n.json new file mode 100644 index 0000000..de27115 --- /dev/null +++ b/interface/i18n/mist.zh-TW.i18n.json @@ -0,0 +1,282 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "關於__app__", + "checkForUpdates": "檢查更新...", + "checkForNodeUpdates": "Check for EtherCore node updates...", + "services": "服務", + "hide": "隱藏 __app__", + "hideOthers": "隱藏其他", + "showAll": "顯示全部", + "quit": "退出__app__" + }, + "edit": { + "label": "編輯", + "undo": "復原", + "redo": "重復", + "cut": "剪下", + "copy": "複製", + "paste": "貼上", + "selectAll": "全選" + }, + "view": { + "label": "檢視", + "fullscreen": "全螢幕", + "default": "Default" + }, + "file": { + "label": "帳號", + "importPresale": "導入帳號", + "newAccount": "新建帳號", + "backup": "備份", + "backupKeyStore": "帳號", + "backupMist": "應用程序數據" + }, + "develop": { + "uploadToSwarm": "上传到Swarm", + "label": "開發", + "devTools": "切換開發者工具", + "devToolsMistUI": "Mist界面", + "devToolsWalletUI": "錢包界面", + "devToolsWebview": "__webview__", + "runTests": "運行測試", + "logFiles": "顯示日誌文件", + "ethereumNode": "以太坊節點", + "network": "網路", + "mainNetwork": "主網路", + "startMining": "⛏ 開啓挖礦(僅限Testnet網路)", + "stopMining": "⛏ 停止挖礦", + "externalNode": "using external node", + "openRemix": "Open Remix IDE", + "nodeMode": "Chain download", + "fullNode": "Store full blockchain", + "lightNode": "Use light Node (experimental!)" + }, + "window": { + "label": "視窗", + "minimize": "最小化", + "close": "關閉", + "toFront": "全部前置" + }, + "help": { + "label": "幫助", + "reportBug": "Report an issue on Github" + } + }, + "errors": { + "nodeConnect": "無法連接節點?查看日誌獲取更多訊息:", + "nodeStartup": "該節點可能無法被啓動,您是否正在運行一個節點?它是否正在更新資料庫?", + "timeSync": { + "title": "您的計算機時間同步不準確!", + "description": "爲了和以太坊網路保持同步,您的電腦時間和伺服器時間需要保持同步。", + "win32": "從系統選項中打開網路時間設置並勾選。詳細資訊參考:http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "爲開啓時間同步伺服器,請通過\"apt-get install ntp\"安裝\"ntp\"。", + "darwin": "爲開啓時間同步,打開時間選項並勾選\"Set the time and date automatically\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in downloaded node!", + "description": "__algorithm__: __hash__\n\nPlease install the __type__ node version __version__ manually." + }, + "legacyChain": { + "title": "Legacy chain detected", + "description": "Your node is currently on the unsupported Ethereum Classic chain. To use this chain use tools provided by the ethereum classic project at\nhttps://ethereumclassic.github.io.\n\nTo revert to the main ethereum chain follow the tutorial here:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "重新載入", + "openDevTools": "打開開發者工具", + "inspectElements": "檢查元素" + }, + "nodeInfo": { + "nodeSyncing": "剩餘__blockDiff__塊", + "blockReceived": "收到新區塊", + "blockNumber": "最新區塊數量", + "timeSinceBlock": "自上一區塊已經過去的時間", + "testnetExplain": "您正處於Testnet測試網路中,請勿發送真正的以太幣到這些地址中", + "peers": "節點", + "checkingWhichNetwork": "Checking network...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "mainnetExplain": "You are on the main EtherCore global network", + "privatenetExplain": "You are on a private net, DO NOT SEND any real ERE to these addresses", + "unknownnetExplain": "Unable to determine which network you are on" + }, + "sidebar": { + "buttons": { + "browser": "瀏覽" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "未設置帳號", + "connect": "Connect" + } + }, + "startScreen": { + "runningNodeFound": "發現正在運行的以太坊節點!", + "startingNode": "正在開啓以太坊節點……", + "startedNode": "正在啓動應用程序……", + "nodeConnectionTimeout": "無法開啓以太坊節點!
如果您已經安裝Geth,使用此命令運行:
geth --ipcpath __path__

或者上報此問題 ", + "nodeBinaryNotFound": "找不到以太坊節點安裝文件!
請事先手動開啓一個節點 ", + "nodeSyncing": "需要同步以太坊節點,請等待……", + "nodeSyncInfo": "正在下載第__displayBlock__塊,共__highestBlock__。", + "nodeSyncConnecting": "正在查找節點……", + "peerSearchTimeout": "跳過節點搜索", + "stoppingNode": "Stopping EtherCore node...", + "nodeStarting": "EtherCore node starting up...", + "nodeStarted": "EtherCore node started", + "nodeConnected": "EtherCore node connected", + "nodeStopping": "EtherCore node stopping...", + "nodeStopped": "EtherCore node stopped", + "nodeError": "EtherCore node connection error :'(", + "unableToBindPort": "EtherCore node cannot run. Is another instance already running?", + "nodeSyncInfoStates": "Downloading block __displayBlock__ of __highestBlock__,
Downloading chain structure __displayState__ of __displayKnownStates__", + "nodeSyncFoundPeers": "Connecting to __peers__ peers...", + "launchApp": "Click To Start!!", + "clientBinaries": { + "scanning": "Checking for node update...", + "downloading": "Downloading new node...", + "loadConfig": "Loading client config...", + "filtering": "Filtering client binaries...", + "done": "EtherCore node up-to-date...", + "error": "Error running downloaded binary." + } + }, + "popupWindows": { + "requestAccount": { + "title": "創建帳號", + "enterPassword": "輸入密碼", + "repeatPassword": "重複密碼", + "creating": "正在生成帳號……", + "errors": { + "passwordMismatch": "您輸入的密碼不符合。", + "passwordTooShort": "Make a longer password" + } + }, + "unlockMasterPassword": { + "title": "輸入主密碼", + "enterPassword": "輸入主密碼", + "unlocking": "正在解鎖……", + "errors": { + "wrongPassword": "密碼錯誤,請重試。" + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "發送交易", + "contractExecution": "執行合約", + "createContract": "創建合約" + }, + "contractExecutionInfo": "您即將執行該合約上的一個函數,這可能需要會轉走您輸入的數量。", + "contractCreationInfo": "您即將用提供的資料創建一個合約。", + "enterPassword": "輸入密碼以確認該交易", + "unlocking": "正在確認……", + "createContract": "創建合約", + "estimatedFee": "預計消耗費用", + "estimatedGasError": "資料無法被執行,因此這將消耗所有提供的Gas。", + "gasPrice": "Gas價格", + "perMillionGas": "以太幣/每百萬gas", + "gasLimit": "提供最大費用", + "data": "數據", + "buttons": { + "sendTransaction": "發送交易" + }, + "errors": { + "connectionTimeout": "無法連接該節點,後台節點是否崩潰了?", + "wrongPassword": "密碼錯誤", + "multipleKeysMatchAddress": "Multiple keys match address. Please remove duplicates from keystore (menu -> File -> Backup -> Accounts)", + "insufficientFundsForGas": "Insufficient funds in main account (etherbase) to pay for gas", + "sameAccount": "Can't send to itself" + }, + "transactionThrow": "The contract won't allow this transaction to be executed", + "noEstimate": "We couldn't estimate the gas.", + "parameters": "Parameters", + "showRawBytecode": "show raw data", + "showDecodedParameters": "show decoded parameters", + "lookupData": "Try to decode data", + "lookupDataExplainer": "Look this up on the internet", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount." + }, + "onboarding": { + "description": "以太坊是一個用於在區塊鏈上創建應用的去中心化平台:一種用於轉移價值和資產,永遠存在並且無法被篡改的軟體", + "goToTestnet": "使用測試網路 (Rinkeby)", + "goToTestnetDescription": "請放心在沙盒測試網路中測試該技術,無需使用真正的以太幣。", + "gotoMainnet": "使用主網路", + "gotoMainnetDescription": "您需要一些以太幣來創建和執行合約。別擔心,我們將幫您獲取一些……", + "doYouHaveAWalletFile": "您擁有一個錢包文件嗎?", + "walletFileDescription": "

如果您參與了2014年的以太坊預售,您應該有一個文件名爲ethereum_wallet_backup.json的錢包文件。在您購買後已被下載並且也發送到您信箱。

", + "dropFilesHere": "預售文件拖入此處", + "creating": "正在創建……", + "importing": "正在匯入……", + "skip": "跳過該步驟", + "next": "下一個", + "protectTitle": "保護您的帳號", + "protectDescription": "爲您的新帳號選擇一個密碼。請像保持您家鑰匙一樣保證密碼強度足夠安全!", + "accountTitle": "正在裝載!", + "accountTitleTestnet": "挖到一些以太幣!", + "etherDescription": "以太坊網路是基於一種叫做“以太幣”的代幣。您需要一點以太幣來嘗試在以太坊網路上的任何操作。", + "loadItDescription": "如果您已經擁有比特幣或者任何其他加密貨幣,您可以使用changelly來方便地轉換爲以太幣。

我們推薦您存入0.25到1以太幣.", + "mineItDescription": "如果您在testnet測試網路中,您可以自己挖掘一些以太幣,點擊開發選單並選擇開啓挖礦
請勿將真正的以太幣發往該地址!", + "you": "您本人", + "etherbase": "主帳號", + "depositBitcoin": "存入比特幣", + "learnIt": "在等待期間學習一下", + "downloadingBlocks": "正在下載區塊", + "tutorial1Description": "

現在您只需等待下載完成。這裏是一些閱讀推薦:

創造您自己的貨幣

創造一個固定發行量的加密貨幣,這些代幣代表真正的世界資產,等等

", + "tutorial2Description": "

創建一個群眾募資

爲一個共同的目標籌集資金,完全可信而無需第三方擔保。繞開傳統融資系統的障礙,通過區塊鏈直接和出資人共同籌資建立一個機構。

", + "tutorial3Description": "

區塊鏈機構

創建一個自治的機構,並且制定關於資金如何使用以太誰能做決定的不可違背的規則,讓您的贊助人在如何使用資金上發揮積極作用。

", + "buttons": { + "showPassword": "顯示密碼", + "importAccount": "導入帳號", + "launchApp": "啓動應用程式!", + "learnReceipt": "學習本祕訣" + }, + "errors": { + "nodeNotStartedYet": "請等待片刻直到您的節點完全啓動再重新嘗試一次", + "unknownFile": "文件無法識別。", + "wrongPassword": "密碼錯誤。", + "importFailed": "無法匯入該文件,錯誤:__error__" + }, + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "syncMessage": "Block __displayBlock__ of __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ of __highestBlockString__ (Chain structure __statesPercent__%)", + "startingSync": "Getting ready to sync.." + }, + "updateAvailable": { + "newVersionAvailable": "New __name__ version available", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Update and Restart", + "download": "Download new version", + "skipUpdate": "Skip Update", + "notNow": "Ask me later", + "checking": "Checking for updates to __name__...", + "noUpdateFound": "No update found. You are running the latest version of __name__." + }, + "connectAccount": { + "chooseAccountTitle": "Choose account", + "createAccount": "Create new account", + "pinToSidebar": "Pin app to the sidebar", + "connectAccountDescription": "You are sharing your identity with __dappName__. This allows the app to see any public information of your accounts, including balances connected to it." + } + } + }, + "elements": { + "checksumAlert": "該地址格式有效,但是由於沒有安全機制保證您不會拼寫錯誤,因此請反覆確認您輸入正確。如果可能的話,請驗證一下安全圖標是否相同。", + "identiconHelper": "這是一個安全圖標,如果地址有任何改動,該圖標將會完全不一樣", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/i18n/mist.zh.i18n.json b/interface/i18n/mist.zh.i18n.json new file mode 100644 index 0000000..5078b17 --- /dev/null +++ b/interface/i18n/mist.zh.i18n.json @@ -0,0 +1,282 @@ +{ + "mist": { + "applicationMenu": { + "app": { + "label": "__app__", + "about": "关于__app__", + "checkForUpdates": "检测更新...", + "checkForNodeUpdates": "Check for EtherCore node updates...", + "services": "服务", + "hide": "隐藏 __app__", + "hideOthers": "隐藏 其它", + "showAll": "显示 全部", + "quit": "退出__app__" + }, + "edit": { + "label": "编辑", + "undo": "撤销", + "redo": "重做", + "cut": "剪切", + "copy": "复制", + "paste": "粘帖", + "selectAll": "全选" + }, + "view": { + "label": "视图", + "fullscreen": "全屏切换", + "default": "Default" + }, + "file": { + "label": "账户", + "importPresale": "导入账户", + "newAccount": "新建账户", + "backup": "备份", + "backupKeyStore": "账户", + "backupMist": "应用程序数据" + }, + "develop": { + "uploadToSwarm": "上传到Swarm", + "label": "开发", + "devTools": "切换开发者工具", + "devToolsMistUI": "Mist界面", + "devToolsWalletUI": "钱包界面", + "devToolsWebview": "__webview__", + "runTests": "运行测试", + "logFiles": "显示日志文件", + "ethereumNode": "以太坊节点", + "network": "网络", + "mainNetwork": "主网络", + "startMining": "⛏ 开启挖矿(仅限Testnet网络)", + "stopMining": "⛏ 停止挖矿", + "externalNode": "using external node", + "openRemix": "Open Remix IDE", + "nodeMode": "Chain download", + "fullNode": "Store full blockchain", + "lightNode": "Use light Node (experimental!)" + }, + "window": { + "label": "窗口", + "minimize": "最小化", + "close": "关闭", + "toFront": "全部前置" + }, + "help": { + "label": "帮助", + "reportBug": "Report an issue on Github" + } + }, + "errors": { + "nodeConnect": "无法连接节点?查看日志获取更多信息:", + "nodeStartup": "该节点可能无法被启动,你是否正在运行一个节点?它是否正在更新数据库?", + "timeSync": { + "title": "你的计算机时间同步不准确!", + "description": "为了和以太坊网络保持同步,你的计算机时间和服务器时间需要保持同步。", + "win32": "从系统选项中打开网络时间设置并勾选。详细信息参考:http://www.guidingtech.com/3119/windows-clock-sync/", + "linux": "为开启时间同步服务器,请通过\"apt-get install ntp\"安装\"ntp\"。", + "darwin": "为开启时间同步,打开时间选项并勾选\"Set the time and date automatically\"." + }, + "nodeChecksumMismatch": { + "title": "Checksum mismatch in downloaded node!", + "description": "__algorithm__: __hash__\n\nPlease install the __type__ node version __version__ manually." + }, + "legacyChain": { + "title": "Legacy chain detected", + "description": "Your node is currently on the unsupported Ethereum Classic chain. To use this chain use tools provided by the ethereum classic project at\nhttps://ethereumclassic.github.io.\n\nTo revert to the main ethereum chain follow the tutorial here:\nhttps://github.com/ethereum/mist/releases/0.8.2" + } + }, + "rightClick": { + "reload": "重新载入", + "openDevTools": "打开开发者工具", + "inspectElements": "页面检测" + }, + "nodeInfo": { + "nodeSyncing": "剩余__blockDiff__块", + "blockReceived": "收到新块", + "blockNumber": "最新的块数量", + "timeSinceBlock": "自上一块已经过去的时间", + "testnetExplain": "你正处于Testnet测试网络中,请勿发送真正的以太币到这些地址中", + "peers": "节点", + "checkingWhichNetwork": "Checking network...", + "mainNetwork": "Main-net", + "testNetwork": "Test-net", + "privateNetwork": "Private-net", + "mainnetExplain": "You are on the main EtherCore global network", + "privatenetExplain": "You are on a private net, DO NOT SEND any real ERE to these addresses", + "unknownnetExplain": "Unable to determine which network you are on" + }, + "sidebar": { + "buttons": { + "browser": "浏览" + } + }, + "browserBar": { + "buttons": { + "noAccounts": "未设置账户", + "connect": "Connect" + } + }, + "startScreen": { + "runningNodeFound": "发现正在运行的以太坊节点!", + "startingNode": "正在开启以太坊节点……", + "startedNode": "正在启动应用程序……", + "nodeConnectionTimeout": "无法开启以太坊节点!
如果你已经安装Geth,使用此命令运行:
geth --ipcpath __path__

或者上报此问题 ", + "nodeBinaryNotFound": "找不到以太坊节点安装文件!
请事先手动开启一个节点 ", + "nodeSyncing": "需要同步以太坊节点,请等待……", + "nodeSyncInfo": "正在下载第__displayBlock__块,共__highestBlock__。", + "nodeSyncConnecting": "正在查找节点……", + "peerSearchTimeout": "跳过节点搜索", + "stoppingNode": "Stopping EtherCore node...", + "nodeStarting": "EtherCore node starting up...", + "nodeStarted": "EtherCore node started", + "nodeConnected": "EtherCore node connected", + "nodeStopping": "EtherCore node stopping...", + "nodeStopped": "EtherCore node stopped", + "nodeError": "EtherCore node connection error :'(", + "unableToBindPort": "EtherCore node cannot run. Is another instance already running?", + "nodeSyncInfoStates": "Downloading block __displayBlock__ of __highestBlock__,
Downloading chain structure __displayState__ of __displayKnownStates__", + "nodeSyncFoundPeers": "Connecting to __peers__ peers...", + "launchApp": "Click To Start!!", + "clientBinaries": { + "scanning": "Checking for node update...", + "downloading": "Downloading new node...", + "loadConfig": "Loading client config...", + "filtering": "Filtering client binaries...", + "done": "EtherCore node up-to-date...", + "error": "Error running downloaded binary." + } + }, + "popupWindows": { + "requestAccount": { + "title": "创建账户", + "enterPassword": "输入密码", + "repeatPassword": "重复密码", + "creating": "正在生成账户……", + "errors": { + "passwordMismatch": "你输入的密码不匹配。", + "passwordTooShort": "Make a longer password" + } + }, + "unlockMasterPassword": { + "title": "输入主密码", + "enterPassword": "输入主密码", + "unlocking": "正在解锁……", + "errors": { + "wrongPassword": "密码错误,请重试。" + } + }, + "sendTransactionConfirmation": { + "title": { + "sendTransaction": "发送交易", + "contractExecution": "执行合约", + "createContract": "创建合约" + }, + "contractExecutionInfo": "你即将执行该合约上的一个函数,这可能需要会转走你输入的数量。", + "contractCreationInfo": "你即将用提供的数据创建一个合约。", + "enterPassword": "输入密码以确认该交易", + "unlocking": "正在确认……", + "createContract": "创建合约", + "estimatedFee": "预计消耗费用", + "estimatedGasError": "数据无法被执行,因此这将消耗所有提供的Gas。", + "gasPrice": "Gas价格", + "perMillionGas": "以太币/每百万gas", + "gasLimit": "提供最大费用", + "data": "数据", + "buttons": { + "sendTransaction": "发送交易" + }, + "errors": { + "connectionTimeout": "无法连接该节点,后台节点是否可能崩溃了?", + "wrongPassword": "密码错误", + "multipleKeysMatchAddress": "Multiple keys match address. Please remove duplicates from keystore (menu -> File -> Backup -> Accounts)", + "insufficientFundsForGas": "Insufficient funds in main account (etherbase) to pay for gas", + "sameAccount": "Can't send to itself" + }, + "transactionThrow": "The contract won't allow this transaction to be executed", + "noEstimate": "We couldn't estimate the gas.", + "parameters": "Parameters", + "showRawBytecode": "show raw data", + "showDecodedParameters": "show decoded parameters", + "lookupData": "Try to decode data", + "lookupDataExplainer": "Look this up on the internet", + "overBlockGasLimit": "The gas required for this execution could exceed the block gas limit.", + "notEnoughGas": "Gas might not be enough to successfully finish this transaction.
Click here to increase the gas amount." + }, + "onboarding": { + "description": "以太坊是一个用于在区块链上创建应用的去中心化平台:一种用于转移价值和资产,永远存在并且无法被篡改的软件", + "goToTestnet": "使用测试网络 (Rinkeby)", + "goToTestnetDescription": "请放心在沙盒测试网络中测试该技术,无需使用真正的以太币。", + "gotoMainnet": "使用主网络", + "gotoMainnetDescription": "你需要一些以太币来创建和执行合约。别担心,我们将帮你获取一些……", + "doYouHaveAWalletFile": "你拥有一个钱包文件吗?", + "walletFileDescription": "

如果你参与了2014年的以太坊预售,你应该有一个文件名为ethereum_wallet_backup.json的钱包文件。在你购买后已被下载并且也发送到你邮箱。

", + "dropFilesHere": "预售文件拖入此处", + "creating": "正在创建……", + "importing": "正在导入……", + "skip": "跳过该步骤", + "next": "下一个", + "protectTitle": "保护你的账户", + "protectDescription": "为你的新账户选择一个密码。请像保持你家钥匙一样保证密码强度足够安全!", + "accountTitle": "正在装载!", + "accountTitleTestnet": "挖到一些以太币!", + "etherDescription": "以太坊网络是基于一种叫做“以太币”的代币。你需要一点以太币来尝试在以太坊网络上的任何操作。", + "loadItDescription": "如果你已经拥有比特币或者任何其他加密货币,你可以使用changelly来方便地转换为以太币。

我们推荐你存入0.25到1以太币.", + "mineItDescription": "如果你在testnet测试网络中,你可以自己挖掘一些以太币,点击开发菜单并选择开启挖矿
请勿将真正的以太币发往该地址!", + "you": "你本人", + "etherbase": "主账户", + "depositBitcoin": "存入比特币", + "learnIt": "在等待期间学习一下", + "downloadingBlocks": "正在下载区块", + "tutorial1Description": "

现在你只需等待下载完成。这里是一些阅读推荐:

创造你自己的货币

创造一个固定发行量的加密货币,这些代币代表真正的世界资产,等等

", + "tutorial2Description": "

创建一个众筹

为一个共同的目标筹集资金,完全可信而无需第三方担保。绕开传统融资系统的障碍,通过区块链直接和出资人共同筹资建立一个机构。

", + "tutorial3Description": "

区块链机构

创建一个自治的机构,并且制定关于资金如何使用以太谁能做决定的不可违背的规则,让你的赞助人在如何使用资金上发挥积极作用。

", + "buttons": { + "showPassword": "显示密码", + "importAccount": "导入账户", + "launchApp": "启动应用程序!", + "learnReceipt": "学习本秘诀" + }, + "errors": { + "nodeNotStartedYet": "请等待片刻直到你的节点完全启动再重新尝试一次", + "unknownFile": "文件无法识别。", + "wrongPassword": "密码错误。", + "importFailed": "无法导入该文件,错误:__error__" + }, + "buyEther": "Buy Ether", + "viaChangelly": "Accepts cryptocurrency and credit card via Changelly", + "syncMessage": "Block __displayBlock__ of __highestBlockString__", + "syncMessageWithStates": "Block __displayBlock__ of __highestBlockString__ (Chain structure __statesPercent__%)", + "startingSync": "Getting ready to sync.." + }, + "updateAvailable": { + "newVersionAvailable": "New __name__ version available", + "version": "Version", + "downloadURL": "Download URL", + "checksum": "Checksum", + "downloadAndRestart": "Update and Restart", + "download": "Download new version", + "skipUpdate": "Skip Update", + "notNow": "Ask me later", + "checking": "Checking for updates to __name__...", + "noUpdateFound": "No update found. You are running the latest version of __name__." + }, + "connectAccount": { + "chooseAccountTitle": "Choose account", + "createAccount": "Create new account", + "pinToSidebar": "Pin app to the sidebar", + "connectAccountDescription": "You are sharing your identity with __dappName__. This allows the app to see any public information of your accounts, including balances connected to it." + } + } + }, + "elements": { + "checksumAlert": "该地址格式有效,但是由于没有安全机制保证你不会拼写错误,因此请反复确认你输入正确。如果可能的话,请验证一下安全图标是否匹配。", + "identiconHelper": "这是一个安全图标,如果地址有任何改动,该图标将会完全不一样", + "type": { + "address": "Address", + "bool": "Boolean", + "int": "Integer", + "uint": "Natural Number", + "string": "String", + "bytes": "Bytes" + } + } +} diff --git a/interface/package.json b/interface/package.json new file mode 100644 index 0000000..2bc91d9 --- /dev/null +++ b/interface/package.json @@ -0,0 +1,27 @@ +{ + "name": "Mist-Interface", + "version": "0.1.0", + "description": "Mist interface application", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ethercore/desktop-wallet.git" + }, + "keywords": [ + "EtherCore", + "mist", + "web3" + ], + "author": "EtherCore ", + "license": "GPL-3.0", + "bugs": { + "url": "https://github.com/ethercore/desktop-wallet/issues" + }, + "homepage": "https://github.com/ethercore/desktop-wallet#readme", + "dependencies": { + "babel-runtime": "^6.18.0" + } +} diff --git a/interface/project-tap.i18n b/interface/project-tap.i18n new file mode 100644 index 0000000..c0fafaa --- /dev/null +++ b/interface/project-tap.i18n @@ -0,0 +1,7 @@ +{ + "cdn_path": "i18n", + "helper_name": "i18n", + "supported_languages": [ + "ca", "de", "en", "es", "fa", "fr", "it", "ja", "ko", "nb", "nl", "pt", "ru", "sq", "zh", "zh-TW" + ] +} diff --git a/interface/public/icons/browse-icon.png b/interface/public/icons/browse-icon.png new file mode 100644 index 0000000..56b55f1 Binary files /dev/null and b/interface/public/icons/browse-icon.png differ diff --git a/interface/public/icons/browse-icon@2x.png b/interface/public/icons/browse-icon@2x.png new file mode 100644 index 0000000..dcd949b Binary files /dev/null and b/interface/public/icons/browse-icon@2x.png differ diff --git a/interface/public/icons/expand-icon.png b/interface/public/icons/expand-icon.png new file mode 100644 index 0000000..9026f14 Binary files /dev/null and b/interface/public/icons/expand-icon.png differ diff --git a/interface/public/icons/mask-icon.png b/interface/public/icons/mask-icon.png new file mode 100644 index 0000000..8453c1f Binary files /dev/null and b/interface/public/icons/mask-icon.png differ diff --git a/interface/public/icons/mask-icon.svg b/interface/public/icons/mask-icon.svg new file mode 100644 index 0000000..85c277c --- /dev/null +++ b/interface/public/icons/mask-icon.svg @@ -0,0 +1,12 @@ + + + + Mask Copy + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/interface/public/images/anonymous-icon.png b/interface/public/images/anonymous-icon.png new file mode 100644 index 0000000..2874d21 Binary files /dev/null and b/interface/public/images/anonymous-icon.png differ diff --git a/interface/public/images/bg-homestead.jpg b/interface/public/images/bg-homestead.jpg new file mode 100644 index 0000000..fb2fa98 Binary files /dev/null and b/interface/public/images/bg-homestead.jpg differ diff --git a/interface/public/images/bg-metropolis.jpg b/interface/public/images/bg-metropolis.jpg new file mode 100644 index 0000000..3037dfb Binary files /dev/null and b/interface/public/images/bg-metropolis.jpg differ diff --git a/interface/public/images/dmg-background.jpg b/interface/public/images/dmg-background.jpg new file mode 100644 index 0000000..472d194 Binary files /dev/null and b/interface/public/images/dmg-background.jpg differ diff --git a/interface/public/images/onboarding-logo-metal.png b/interface/public/images/onboarding-logo-metal.png new file mode 100644 index 0000000..862163d Binary files /dev/null and b/interface/public/images/onboarding-logo-metal.png differ diff --git a/interface/public/images/tutorial-crowdsale.png b/interface/public/images/tutorial-crowdsale.png new file mode 100644 index 0000000..b7d0881 Binary files /dev/null and b/interface/public/images/tutorial-crowdsale.png differ diff --git a/interface/public/images/tutorial-dao.png b/interface/public/images/tutorial-dao.png new file mode 100644 index 0000000..d0f4149 Binary files /dev/null and b/interface/public/images/tutorial-dao.png differ diff --git a/interface/public/images/tutorial-token.png b/interface/public/images/tutorial-token.png new file mode 100644 index 0000000..a4d73d7 Binary files /dev/null and b/interface/public/images/tutorial-token.png differ diff --git a/interface/yarn.lock b/interface/yarn.lock new file mode 100644 index 0000000..60ebd0b --- /dev/null +++ b/interface/yarn.lock @@ -0,0 +1,18 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +babel-runtime@^6.18.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.25.0.tgz#33b98eaa5d482bb01a8d1aa6b437ad2b01aec41c" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +core-js@^2.4.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.0.tgz#569c050918be6486b3837552028ae0466b717086" + +regenerator-runtime@^0.10.0: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" diff --git a/main.js b/main.js new file mode 100644 index 0000000..e07be37 --- /dev/null +++ b/main.js @@ -0,0 +1,415 @@ +global._ = require('./modules/utils/underscore'); +const { app, dialog, ipcMain, shell, protocol } = require('electron'); +const timesync = require('os-timesync'); +const dbSync = require('./modules/dbSync.js'); +const i18n = require('./modules/i18n.js'); +const logger = require('./modules/utils/logger'); +const Sockets = require('./modules/socketManager'); +const Windows = require('./modules/windows'); +const ClientBinaryManager = require('./modules/clientBinaryManager'); +const UpdateChecker = require('./modules/updateChecker'); +const Q = require('bluebird'); +const windowStateKeeper = require('electron-window-state'); +const log = logger.create('main'); +const Settings = require('./modules/settings'); + +import configureReduxStore from './modules/core/store'; +import { quitApp } from './modules/core/ui/actions'; +import { + setLanguageOnMain, + toggleSwarm +} from './modules/core/settings/actions'; +import { SwarmState } from './modules/core/settings/reducer'; +import swarmNode from './modules/swarmNode.js'; + +Q.config({ + cancellation: true +}); + +global.store = configureReduxStore(); + +Settings.init(); + +const db = (global.db = require('./modules/db')); + +require('./modules/ipcCommunicator.js'); +const appMenu = require('./modules/menuItems'); +const ipcProviderBackend = require('./modules/ipc/ipcProviderBackend.js'); +const ethereumNode = require('./modules/ethereumNode.js'); +const nodeSync = require('./modules/nodeSync.js'); + +// Define global vars; The preloader makes some globals available to the client. +global.webviews = []; +global.mining = false; +global.mode = store.getState().settings.uiMode; +global.icon = `${__dirname}/icons/${global.mode}/icon.png`; +global.dirname = __dirname; +global.i18n = i18n; + +// INTERFACE PATHS +// - WALLET +if (global.mode === 'wallet') { + log.info('Starting in Wallet mode'); + + global.interfaceAppUrl = Settings.inProductionMode + ? `file://${__dirname}/interface/wallet/index.html` + : 'http://localhost:3050'; + global.interfacePopupsUrl = Settings.inProductionMode + ? `file://${__dirname}/interface/index.html` + : 'http://localhost:3000'; + + // - MIST +} else { + log.info('Starting in Mist mode'); + + let url = Settings.inProductionMode + ? `file://${__dirname}/interface/index.html` + : 'http://localhost:3000'; + + if (Settings.cli.resetTabs) { + url += '?reset-tabs=true'; + } + + global.interfaceAppUrl = global.interfacePopupsUrl = url; +} + +// prevent crashes and close gracefully +process.on('uncaughtException', error => { + log.error('UNCAUGHT EXCEPTION', error); + store.dispatch(quitApp()); +}); + +// Quit when all windows are closed. +app.on('window-all-closed', () => store.dispatch(quitApp())); + +// Listen to custom protocol incoming messages, needs registering of URL schemes +app.on('open-url', (e, url) => log.info('Open URL', url)); + +let killedSocketsAndNodes = false; + +app.on('before-quit', async event => { + if (!killedSocketsAndNodes) { + log.info('Defer quitting until sockets and node are shut down'); + + event.preventDefault(); + + // sockets manager + try { + await Sockets.destroyAll(); + store.dispatch({ type: '[MAIN]:SOCKETS:DESTROY' }); + } catch (e) { + log.error('Error shutting down sockets'); + } + + // delay quit, so the sockets can close + setTimeout(async () => { + await ethereumNode.stop(); + store.dispatch({ type: '[MAIN]:ETH_NODE:STOP' }); + + killedSocketsAndNodes = true; + await db.close(); + store.dispatch({ type: '[MAIN]:DB:CLOSE' }); + + store.dispatch(quitApp()); + }, 500); + } else { + log.info('About to quit...'); + } +}); + +let mainWindow; +let splashWindow; + +// This method will be called when Electron has done everything +// initialization and ready for creating browser windows. +app.on('ready', async () => { + // if using HTTP RPC then inform user + if (Settings.rpcMode === 'http') { + dialog.showErrorBox( + 'Insecure RPC connection', + ` +WARNING: You are connecting to an EtherCore node via: ${Settings.rpcHttpPath} + +This is less secure than using local IPC - your passwords will be sent over the wire in plaintext. + +Only do this if you have secured your HTTP connection or you know what you are doing. +` + ); + } + + // initialise the db + try { + await global.db.init(); + store.dispatch({ type: '[MAIN]:DB:INIT' }); + onReady(); + } catch (e) { + log.error(e); + store.dispatch(quitApp()); + } +}); + +protocol.registerStandardSchemes(['bzz']); +store.dispatch({ + type: '[MAIN]:PROTOCOL:REGISTER', + payload: { protocol: 'bzz' } +}); + +async function onReady() { + global.config = db.getCollection('SYS_config'); + + dbSync.initializeListeners(); + + Windows.init(); + + enableSwarmProtocol(); + + if (!Settings.inAutoTestMode) { + await UpdateChecker.run(); + } + + ipcProviderBackend.init(); + + // TODO: Settings.language relies on global.config object being set + store.dispatch(setLanguageOnMain(Settings.language)); + + appMenu(); + + createCoreWindows(); + + checkTimeSync(); + + splashWindow ? splashWindow.on('ready', kickStart) : kickStart(); +} + +function enableSwarmProtocol() { + protocol.registerHttpProtocol( + 'bzz', + (request, callback) => { + if ( + [SwarmState.Disabling, SwarmState.Disabled].includes( + store.getState().settings.swarmState + ) + ) { + const error = global.i18n.t('mist.errors.swarm.notEnabled'); + dialog.showErrorBox('Note', error); + callback({ error }); + store.dispatch({ + type: '[MAIN]:PROTOCOL:ERROR', + payload: { protocol: 'bzz', error } + }); + return; + } + + const redirectPath = `${Settings.swarmURL}/${request.url.replace( + 'bzz:/', + 'bzz://' + )}`; + + if (store.getState().settings.swarmState === SwarmState.Enabling) { + swarmNode.on('started', () => { + callback({ + method: request.method, + referrer: request.referrer, + url: redirectPath + }); + }); + } else { + // Swarm enabled + callback({ + method: request.method, + referrer: request.referrer, + url: redirectPath + }); + } + + store.dispatch({ + type: '[MAIN]:PROTOCOL:REQUEST', + payload: { protocol: 'bzz' } + }); + }, + error => { + if (error) { + log.error(error); + } + } + ); +} + +function createCoreWindows() { + global.defaultWindow = windowStateKeeper({ + defaultWidth: 1024 + 208, + defaultHeight: 720 + }); + + // Create the browser window. + mainWindow = Windows.create('main'); + + // Delegating events to save window bounds on windowStateKeeper + global.defaultWindow.manage(mainWindow.window); + + if (!Settings.inAutoTestMode) { + splashWindow = Windows.create('splash'); + } +} + +function checkTimeSync() { + if (!Settings.skiptimesynccheck) { + timesync.checkEnabled((err, enabled) => { + if (err) { + log.error("Couldn't infer if computer automatically syncs time.", err); + return; + } + + if (!enabled) { + dialog.showMessageBox( + { + type: 'warning', + buttons: ['OK'], + message: global.i18n.t('mist.errors.timeSync.title'), + detail: `${global.i18n.t( + 'mist.errors.timeSync.description' + )}\n\n${global.i18n.t(`mist.errors.timeSync.${process.platform}`)}` + }, + () => {} + ); + } + }); + } +} + +async function kickStart() { + initializeKickStartListeners(); + checkForLegacyChain(); + await ClientBinaryManager.init(); + await ethereumNode.init(); + + if (Settings.enableSwarmOnStart) { + store.dispatch(toggleSwarm()); + } + + if (!ethereumNode.isIpcConnected) { + throw new Error( + "Either the node didn't start or IPC socket failed to connect." + ); + } + log.info('Connected via IPC to node.'); + + // Update menu, to show node switching possibilities + appMenu(); + + if (splashWindow) { + splashWindow.show(); + } + if (!Settings.inAutoTestMode) { + await handleNodeSync(); + } + + await startMainWindow(); +} + +function checkForLegacyChain() { + if ((Settings.loadUserData('daoFork') || '').trim() === 'false') { + dialog.showMessageBox( + { + type: 'warning', + buttons: ['OK'], + message: global.i18n.t('mist.errors.legacyChain.title'), + detail: global.i18n.t('mist.errors.legacyChain.description') + }, + () => { + shell.openExternal('https://github.com/ethercore/desktop-wallet/releases'); + store.dispatch(quitApp()); + } + ); + + throw new Error('Cant start client due to legacy non-Fork setting.'); + } +} + +function initializeKickStartListeners() { + ClientBinaryManager.on('status', (status, data) => { + Windows.broadcast('uiAction_clientBinaryStatus', status, data); + }); + + ethereumNode.on('nodeConnectionTimeout', () => { + Windows.broadcast('uiAction_nodeStatus', 'connectionTimeout'); + }); + + ethereumNode.on('nodeLog', data => { + Windows.broadcast('uiAction_nodeLogText', data.replace(/^.*[0-9]]/, '')); + }); + + ethereumNode.on('state', (state, stateAsText) => { + Windows.broadcast( + 'uiAction_nodeStatus', + stateAsText, + ethereumNode.STATES.ERROR === state ? ethereumNode.lastError : null + ); + }); +} + +function handleNodeSync() { + return new Q((resolve, reject) => { + nodeSync.on('nodeSyncing', result => { + Windows.broadcast('uiAction_nodeSyncStatus', 'inProgress', result); + }); + + nodeSync.on('stopped', () => { + Windows.broadcast('uiAction_nodeSyncStatus', 'stopped'); + }); + + nodeSync.on('error', err => { + log.error('Error syncing node', err); + + reject(err); + }); + + nodeSync.on('finished', () => { + nodeSync.removeAllListeners('error'); + nodeSync.removeAllListeners('finished'); + + resolve(); + }); + }); +} + +function startMainWindow() { + log.info(`Loading Interface at ${global.interfaceAppUrl}`); + initializeMainWindowListeners(); + initializeTabs(); +} + +function initializeMainWindowListeners() { + mainWindow.on('ready', () => { + if (splashWindow) { + splashWindow.close(); + } + mainWindow.show(); + }); + + mainWindow.load(global.interfaceAppUrl); + + mainWindow.on('closed', () => store.dispatch(quitApp())); +} + +function initializeTabs() { + const Tabs = global.db.getCollection('UI_tabs'); + const sortedTabs = + Tabs.getDynamicView('sorted_tabs') || Tabs.addDynamicView('sorted_tabs'); + sortedTabs.applySimpleSort('position', false); + + const refreshMenu = () => { + clearTimeout(global._refreshMenuFromTabsTimer); + + global._refreshMenuFromTabsTimer = setTimeout(() => { + log.debug('Refresh menu with tabs'); + global.webviews = sortedTabs.data(); + appMenu(global.webviews); + store.dispatch({ type: '[MAIN]:MENU:REFRESH' }); + }, 1000); + }; + + Tabs.on('insert', refreshMenu); + Tabs.on('update', refreshMenu); + Tabs.on('delete', refreshMenu); +} diff --git a/modules/abi.js b/modules/abi.js new file mode 100644 index 0000000..ec9bfa9 --- /dev/null +++ b/modules/abi.js @@ -0,0 +1,55 @@ +/** +Decodes Data into values, for a given signature. + +@module ABI +*/ +const _ = global._; +const { ipcMain: ipc } = require('electron'); +const abi = require('ethereumjs-abi'); + +function isHexType(type) { + return _.includes(['address', 'bytes'], type) || type.match(/bytes\d+/g); +} + +function padLeft(string, chars) { + return new Array(chars - string.length + 1).join('0') + string; +} + +ipc.on('backendAction_decodeFunctionSignature', (event, _signature, _data) => { + const data = _data.slice(10, _data.length); + const signature = _signature.match(/\((.+)\)/i); + + if (!signature) return; + + const paramTypes = signature[1].split(','); + + try { + const paramsResponse = abi.rawDecode(paramTypes, new Buffer(data, 'hex')); + const paramsDictArr = []; + + // Turns addresses into proper hex string + // Turns numbers into their decimal string version + paramTypes.forEach((type, index) => { + const conversionFlag = isHexType(type) ? 'hex' : null; + const prefix = isHexType(type) ? '0x' : ''; + + paramsResponse[index] = paramsResponse[index].toString(conversionFlag); + + const res = type.match(/bytes(\d+)/i); + if (type === 'address') { + paramsResponse[index] = padLeft(paramsResponse[index], 40); + } else if (res) { + paramsResponse[index] = padLeft( + paramsResponse[index], + Number(res[1]) * 2 + ); + } + + paramsDictArr.push({ type, value: prefix + paramsResponse[index] }); + }); + + event.sender.send('uiAction_decodedFunctionSignatures', paramsDictArr); + } catch (e) { + console.warn('ABI.js Warning:', e.message); + } +}); diff --git a/modules/blurOverlay.js b/modules/blurOverlay.js new file mode 100644 index 0000000..7537fc8 --- /dev/null +++ b/modules/blurOverlay.js @@ -0,0 +1,18 @@ +const Windows = require('./windows'); + +class BlurOverlay { + static enable() { + BlurOverlay.setBlurOverlay(true); + } + + static disable() { + BlurOverlay.setBlurOverlay(false); + } + + static setBlurOverlay(flag) { + const mainWindow = Windows.getByType('main'); + mainWindow.send('uiAction_enableBlurOverlay', flag); + } +} + +module.exports = BlurOverlay; diff --git a/modules/clientBinaryManager.js b/modules/clientBinaryManager.js new file mode 100644 index 0000000..1bfb5ad --- /dev/null +++ b/modules/clientBinaryManager.js @@ -0,0 +1,352 @@ +const _ = global._; +const Q = require('bluebird'); +const fs = require('fs'); +const { app, dialog } = require('electron'); +const got = require('got'); +const path = require('path'); +const Settings = require('./settings'); +const Windows = require('./windows'); +const ClientBinaryManager = require('ethereum-client-binaries').Manager; +const EventEmitter = require('events').EventEmitter; + +const log = require('./utils/logger').create('ClientBinaryManager'); + +// should be 'https://raw.githubusercontent.com/ethercore/desktop-wallet/master/clientBinaries.json' +const BINARY_URL = + 'https://raw.githubusercontent.com/ethercore/desktop-wallet/master/clientBinaries.json'; + +const ALLOWED_DOWNLOAD_URLS_REGEX = /^https:\/\/(?:(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)?ethercore\.org\/|github\.com\/|gethstore\.blob\.core\.windows\.net\/|bintray\.com\/artifact\/download\/karalabe\/ethereum\/)(?:.+)/; // eslint-disable-line max-len + +class Manager extends EventEmitter { + constructor() { + super(); + + this._availableClients = {}; + } + + init(restart) { + log.info('Initializing...'); + + // check every hour + setInterval(() => this._checkForNewConfig(true), 1000 * 60 * 60); + + return this._checkForNewConfig(restart); + } + + getClient(clientId) { + return this._availableClients[clientId.toLowerCase()]; + } + + _writeLocalConfig(json) { + log.info('Write new client binaries local config to disk ...'); + + fs.writeFileSync( + path.join(Settings.userDataPath, 'clientBinaries.json'), + JSON.stringify(json, null, 2) + ); + } + + _checkForNewConfig(restart) { + const nodeType = 'Geth'; + let binariesDownloaded = false; + let nodeInfo; + + log.info(`Checking for new client binaries config from: ${BINARY_URL}`); + + this._emit('loadConfig', 'Fetching remote client config'); + + // fetch config + return got(BINARY_URL, { + timeout: 3000, + json: true + }) + .then(res => { + if (!res || _.isEmpty(res.body)) { + throw new Error('Invalid fetch result'); + } else { + return res.body; + } + }) + .catch(err => { + log.warn('Error fetching client binaries config from repo', err); + }) + .then(latestConfig => { + if (!latestConfig) return; + + let localConfig; + let skipedVersion; + const nodeVersion = latestConfig.clients[nodeType].version; + + this._emit('loadConfig', 'Fetching local config'); + + try { + // now load the local json + localConfig = JSON.parse( + fs + .readFileSync( + path.join(Settings.userDataPath, 'clientBinaries.json') + ) + .toString() + ); + } catch (err) { + log.warn( + `Error loading local config - assuming this is a first run: ${err}` + ); + + if (latestConfig) { + localConfig = latestConfig; + + this._writeLocalConfig(localConfig); + } else { + throw new Error( + 'Unable to load local or remote config, cannot proceed!' + ); + } + } + + try { + skipedVersion = fs + .readFileSync( + path.join(Settings.userDataPath, 'skippedNodeVersion.json') + ) + .toString(); + } catch (err) { + log.info('No "skippedNodeVersion.json" found.'); + } + + // prepare node info + const platform = process.platform + .replace('darwin', 'mac') + .replace('win32', 'win') + .replace('freebsd', 'linux') + .replace('sunos', 'linux'); + const binaryVersion = + latestConfig.clients[nodeType].platforms[platform][process.arch]; + const checksums = _.pick(binaryVersion.download, 'sha256', 'md5'); + const algorithm = _.keys(checksums)[0].toUpperCase(); + const hash = _.values(checksums)[0]; + + // get the node data, to be able to pass it to a possible error + nodeInfo = { + type: nodeType, + version: nodeVersion, + checksum: hash, + algorithm + }; + + // if new config version available then ask user if they wish to update + if ( + latestConfig && + JSON.stringify(localConfig) !== JSON.stringify(latestConfig) && + nodeVersion !== skipedVersion + ) { + return new Q(resolve => { + log.debug( + 'New client binaries config found, asking user if they wish to update...' + ); + + const wnd = Windows.createPopup( + 'clientUpdateAvailable', + { + sendData: { + uiAction_sendData: { + name: nodeType, + version: nodeVersion, + checksum: `${algorithm}: ${hash}`, + downloadUrl: binaryVersion.download.url, + restart + } + } + }, + update => { + // update + if (update === 'update') { + this._writeLocalConfig(latestConfig); + + resolve(latestConfig); + + // skip + } else if (update === 'skip') { + fs.writeFileSync( + path.join(Settings.userDataPath, 'skippedNodeVersion.json'), + nodeVersion + ); + + resolve(localConfig); + } + + wnd.close(); + } + ); + + // if the window is closed, simply continue and as again next time + wnd.on('close', () => { + resolve(localConfig); + }); + }); + } + + return localConfig; + }) + .then(localConfig => { + if (!localConfig) { + log.info( + 'No config for the ClientBinaryManager could be loaded, using local clientBinaries.json.' + ); + + const localConfigPath = path.join( + Settings.userDataPath, + 'clientBinaries.json' + ); + localConfig = fs.existsSync(localConfigPath) + ? require(localConfigPath) + : require('../clientBinaries.json'); // eslint-disable-line no-param-reassign, global-require, import/no-dynamic-require, import/no-unresolved + } + + // scan for node + const mgr = new ClientBinaryManager(localConfig); + mgr.logger = log; + + this._emit('scanning', 'Scanning for binaries'); + + return mgr + .init({ + folders: [ + path.join(Settings.userDataPath, 'binaries', 'Geth', 'unpacked'), + path.join(Settings.userDataPath, 'binaries', 'Eth', 'unpacked') + ] + }) + .then(() => { + const clients = mgr.clients; + + this._availableClients = {}; + + const available = _.filter(clients, c => !!c.state.available); + + if (!available.length) { + if (_.isEmpty(clients)) { + throw new Error( + 'No client binaries available for this system!' + ); + } + + this._emit('downloading', 'Downloading binaries'); + + return Q.map(_.values(clients), c => { + binariesDownloaded = true; + + return mgr.download(c.id, { + downloadFolder: path.join(Settings.userDataPath, 'binaries'), + urlRegex: ALLOWED_DOWNLOAD_URLS_REGEX + }); + }); + } + }) + .then(() => { + this._emit('filtering', 'Filtering available clients'); + + _.each(mgr.clients, client => { + if (client.state.available) { + const idlcase = client.id.toLowerCase(); + + this._availableClients[idlcase] = { + binPath: + Settings[`${idlcase}Path`] || client.activeCli.fullPath, + version: client.version + }; + } + }); + + // restart if it downloaded while running + if (restart && binariesDownloaded) { + log.info('Restarting app ...'); + app.relaunch(); + app.quit(); + } + + this._emit('done'); + }); + }) + .catch(err => { + log.error(err); + + this._emit('error', err.message); + + // show error + if (err.message.indexOf('Hash mismatch') !== -1) { + // show hash mismatch error + dialog.showMessageBox( + { + type: 'warning', + buttons: ['OK'], + message: global.i18n.t('mist.errors.nodeChecksumMismatch.title'), + detail: global.i18n.t( + 'mist.errors.nodeChecksumMismatch.description', + { + type: nodeInfo.type, + version: nodeInfo.version, + algorithm: nodeInfo.algorithm, + hash: nodeInfo.checksum + } + ) + }, + () => { + app.quit(); + } + ); + + // throw so the main.js can catch it + throw err; + } + }); + } + + _emit(status, msg) { + log.debug(`Status: ${status} - ${msg}`); + + this.emit('status', status, msg); + } + + _resolveEthBinPath() { + log.info('Resolving path to Eth client binary ...'); + + let platform = process.platform; + + // "win32" -> "win" (because nodes are bundled by electron-builder) + if (platform.indexOf('win') === 0) { + platform = 'win'; + } else if (platform.indexOf('darwin') === 0) { + platform = 'mac'; + } + + log.debug(`Platform: ${platform}`); + + let binPath = path.join( + __dirname, + '..', + 'nodes', + 'eth', + `${platform}-${process.arch}` + ); + + if (Settings.inProductionMode) { + // get out of the ASAR + binPath = binPath.replace('nodes', path.join('..', '..', 'nodes')); + } + + binPath = path.join(path.resolve(binPath), 'eth'); + + if (platform === 'win') { + binPath += '.exe'; + } + + log.info(`Eth client binary path: ${binPath}`); + + this._availableClients.eth = { + binPath, + version: '1.3.0' + }; + } +} + +module.exports = new Manager(); diff --git a/modules/core/rootReducer.js b/modules/core/rootReducer.js new file mode 100644 index 0000000..2f909dc --- /dev/null +++ b/modules/core/rootReducer.js @@ -0,0 +1,8 @@ +import { combineReducers } from 'redux'; +import settings from './settings/reducer'; +import ui from './ui/reducer'; + +export default combineReducers({ + settings, + ui +}); diff --git a/modules/core/settings/actions.js b/modules/core/settings/actions.js new file mode 100644 index 0000000..7ecd4f8 --- /dev/null +++ b/modules/core/settings/actions.js @@ -0,0 +1,181 @@ +const Settings = require('../../settings'); + +import logger from '../../utils/logger'; +import swarmNode from '../../swarmNode'; +import { SwarmState } from './reducer'; + +const swarmLog = logger.create('swarm'); + +export function syncFlags(argv) { + return { type: '[MAIN]:CLI_FLAGS:SYNC', payload: { cliFlags: argv } }; +} + +export function syncBuildConfig(key, value) { + return { + type: '[MAIN]:BUILD_CONFIG:SYNC', + payload: { [key]: value } + }; +} + +export function setLanguage(lang, browserWindow) { + return dispatch => { + dispatch({ type: '[MAIN]:SET_LANGUAGE:START' }); + dispatch(setLanguageOnMain(lang)); + dispatch(setLanguageOnClient(lang, browserWindow)); + dispatch(setAcceptLanguageHeader(lang, browserWindow)); + dispatch(resetMenu(lang)); + dispatch({ type: '[MAIN]:SET_LANGUAGE:FINISH' }); + }; +} + +export function setLanguageOnMain(lang) { + return dispatch => { + dispatch({ type: '[MAIN]:SET_LANGUAGE_ON_MAIN:START' }); + try { + i18n.changeLanguage(lang.substr(0, 5)); + dispatch({ + type: '[MAIN]:SET_LANGUAGE_ON_MAIN:SUCCESS', + payload: { i18n: lang } + }); + } catch (error) { + dispatch({ type: '[MAIN]:SET_LANGUAGE_ON_MAIN:FAILURE', error }); + } + }; +} + +export function setLanguageOnClient(lang, browserWindow) { + return dispatch => { + dispatch({ type: '[MAIN]:SET_LANGUAGE_ON_CLIENT:START' }); + try { + browserWindow.webContents.executeJavaScript( + `TAPi18n.setLanguage("${lang}");` + ); + dispatch({ + type: '[MAIN]:SET_LANGUAGE_ON_CLIENT:SUCCESS', + payload: { i18n: lang } + }); + } catch (error) { + dispatch({ type: '[MAIN]:SET_LANGUAGE_ON_CLIENT:FAILURE', error }); + } + }; +} + +export function setAcceptLanguageHeader(lang, browserWindow) { + return dispatch => { + dispatch({ type: '[MAIN]:SET_ACCEPT_LANGUAGE_HEADER:START' }); + try { + const session = browserWindow.webContents.session; + session.setUserAgent(session.getUserAgent(), lang); + dispatch({ type: '[MAIN]:SET_ACCEPT_LANGUAGE_HEADER:SUCCESS' }); + } catch (error) { + dispatch({ + type: '[MAIN]:SET_ACCEPT_LANGUAGE_HEADER:FAILURE', + error + }); + } + }; +} + +export function resetMenu(lang) { + return dispatch => { + dispatch({ type: '[MAIN]:RESET_MENU:START' }); + try { + if (lang) { + Settings.language = lang; + } + + const appMenu = require('../../menuItems'); + appMenu(global.webviews); + + dispatch({ type: '[MAIN]:RESET_MENU:SUCCESS' }); + } catch (error) { + dispatch({ type: '[MAIN]:RESET_MENU:FAILURE', error }); + } + }; +} + +export function getLanguage(event) { + return (dispatch, getState) => { + dispatch({ type: '[MAIN]:GET_LANGUAGE:START' }); + try { + const i18n = getState().settings.i18n; + event.returnValue = i18n; + dispatch({ + type: '[MAIN]:GET_LANGUAGE:SUCCESS', + payload: { i18n } + }); + } catch (error) { + dispatch({ type: '[MAIN]:GET_LANGUAGE:FAILURE', error }); + } + }; +} + +export function toggleSwarm(event) { + return (dispatch, getState) => { + if ( + [SwarmState.Enabled, SwarmState.Enabling].includes( + getState().settings.swarmState + ) + ) { + dispatch({ type: '[MAIN]:SWARM:STOP' }); + + try { + swarmNode.on('stopping', () => { + swarmLog.info('Stopping Swarm'); + dispatch({ type: '[MAIN]:SWARM:DISABLING' }); + }); + + swarmNode.on('stopped', () => { + swarmLog.info('Swarm stopped'); + dispatch({ type: '[MAIN]:SWARM:DISABLED' }); + dispatch(resetMenu()); + }); + + swarmNode.stop(); + + if (getState().settings.swarmEnableOnStart) { + Settings.enableSwarmOnStart = false; + dispatch({ type: '[MAIN]:SWARM:DISABLE_ON_START' }); + } + } catch (error) { + dispatch({ type: '[MAIN]:SWARM:FAILURE', error }); + swarmLog.error(error); + } + } else { + dispatch({ type: '[MAIN]:SWARM:START' }); + + try { + swarmNode.on('starting', () => { + swarmLog.info('Starting Swarm'); + dispatch({ type: '[MAIN]:SWARM:ENABLING' }); + }); + + swarmNode.on('downloadProgress', progress => { + swarmLog.info( + `Downloading Swarm binary: ${(progress * 100).toFixed(1)}%` + ); + }); + + swarmNode.on('started', () => { + swarmLog.info('Swarm started'); + dispatch({ type: '[MAIN]:SWARM:ENABLED' }); + dispatch(resetMenu()); + }); + + swarmNode.init(); + + if (!getState().settings.swarmEnableOnStart) { + Settings.enableSwarmOnStart = true; + dispatch({ type: '[MAIN]:SWARM:ENABLE_ON_START' }); + } + } catch (error) { + dispatch({ type: '[MAIN]:SWARM:FAILURE', error }); + swarmLog.error(error); + } + } + }; +} + +export function setSwarmEnableOnStart() { + return { type: '[MAIN]:SWARM:ENABLE_ON_START' }; +} diff --git a/modules/core/settings/reducer.js b/modules/core/settings/reducer.js new file mode 100644 index 0000000..3f734e8 --- /dev/null +++ b/modules/core/settings/reducer.js @@ -0,0 +1,79 @@ +export const SwarmState = { + Enabled: 'Enabled', + Enabling: 'Enabling', + Disabling: 'Disabling', + Disabled: 'Disabled', + Error: 'Error' +}; + +export const initialState = { + appVersion: '', + autoTestMode: false, + dbInit: false, + dbSync: false, + ignoreGpuBlacklist: false, + i18n: '', + ipcProviderBackendInit: false, + productionMode: null, + protocols: [], + rpcMode: '', + swarmState: SwarmState.Disabled, + swarmEnableOnStart: false, + uiMode: '', + updateCheckerRan: false, + cliFlags: {} +}; + +const settings = (state = initialState, action) => { + switch (action.type) { + case '[MAIN]:DB:INIT': + return Object.assign({}, state, { dbInit: true }); + case '[MAIN]:DB:SYNC_TO_BACKEND': + return Object.assign({}, state, { dbSync: true }); + case '[MAIN]:PROTOCOL:REGISTER': + return Object.assign({}, state, { + protocols: state.protocols.concat(action.payload.protocol) + }); + case '[MAIN]:BUILD_CONFIG:SYNC': + const key = Object.keys(action.payload)[0]; + return Object.assign({}, state, { [key]: action.payload[key] }); + case '[MAIN]:IGNORE_GPU_BLACKLIST:SET': + return Object.assign({}, state, { ignoreGpuBlacklist: true }); + case '[MAIN]:TEST_MODE:SET': + return Object.assign({}, state, { autoTestMode: true }); + case '[MAIN]:CLI_FLAGS:SYNC': + return Object.assign({}, state, { + cliFlags: action.payload.cliFlags + }); + case '[MAIN]:SET_LANGUAGE_ON_MAIN:SUCCESS': + return Object.assign({}, state, { i18n: action.payload.i18n }); + case '[MAIN]:SWARM:ENABLING': + return Object.assign({}, state, { + swarmState: SwarmState.Enabling + }); + case '[MAIN]:SWARM:ENABLED': + return Object.assign({}, state, { swarmState: SwarmState.Enabled }); + case '[MAIN]:SWARM:DISABLING': + return Object.assign({}, state, { + swarmState: SwarmState.Disabling + }); + case '[MAIN]:SWARM:DISABLED': + return Object.assign({}, state, { + swarmState: SwarmState.Disabled + }); + case '[MAIN]:SWARM:FAILURE': + return Object.assign({}, state, { swarmState: SwarmState.Error }); + case '[MAIN]:SWARM:ENABLE_ON_START': + return Object.assign({}, state, { swarmEnableOnStart: true }); + case '[MAIN]:SWARM:DISABLE_ON_START': + return Object.assign({}, state, { swarmEnableOnStart: false }); + case '[MAIN]:UPDATE_CHECKER:FINISH': + return Object.assign({}, state, { updateCheckerRan: true }); + case '[MAIN]:IPC_PROVIDER_BACKEND:FINISH': + return Object.assign({}, state, { ipcProviderBackendInit: true }); + default: + return state; + } +}; + +export default settings; diff --git a/modules/core/store.js b/modules/core/store.js new file mode 100644 index 0000000..7d439ea --- /dev/null +++ b/modules/core/store.js @@ -0,0 +1,17 @@ +import { createStore, applyMiddleware } from 'redux'; +import { forwardToRenderer, replayActionMain } from 'electron-redux'; +import { composeWithDevTools } from 'remote-redux-devtools'; +import thunk from 'redux-thunk'; +import { app } from 'electron'; +import rootReducer from './rootReducer'; + +export default function configureReduxStore() { + const store = createStore( + rootReducer, + composeWithDevTools(applyMiddleware(thunk, forwardToRenderer)) + ); + + replayActionMain(store); + + return store; +} diff --git a/modules/core/ui/actions.js b/modules/core/ui/actions.js new file mode 100644 index 0000000..9ab6609 --- /dev/null +++ b/modules/core/ui/actions.js @@ -0,0 +1,29 @@ +import { app } from 'electron'; + +export function quitApp() { + return dispatch => { + dispatch({ type: '[MAIN]:APP_QUIT:START' }); + try { + app.quit(); + dispatch({ type: '[MAIN]:APP_QUIT:SUCCESS' }); + } catch (error) { + dispatch({ type: '[MAIN]:APP_QUIT:FAILURE', error }); + } + }; +} + +export function openWindow(windowType) { + return { type: '[MAIN]:WINDOW:OPEN', payload: { windowType } }; +} + +export function closeWindow(windowType) { + return { type: '[MAIN]:WINDOW:CLOSE', payload: { windowType } }; +} + +export function reuseGenericWindow(actingType) { + return { type: '[MAIN]:GENERIC_WINDOW:REUSE', payload: { actingType } }; +} + +export function resetGenericWindow() { + return { type: '[MAIN]:GENERIC_WINDOW:RESET' }; +} diff --git a/modules/core/ui/reducer.js b/modules/core/ui/reducer.js new file mode 100644 index 0000000..cf294d2 --- /dev/null +++ b/modules/core/ui/reducer.js @@ -0,0 +1,41 @@ +import uniq from 'lodash/uniq'; + +export const initialState = { + appQuit: false, + genericWindowActingType: '', + windowsInit: false, + windowsOpen: [] +}; + +const ui = (state = initialState, action) => { + switch (action.type) { + case '[MAIN]:APP_QUIT:SUCCESS': + return Object.assign({}, state, { appQuit: true }); + case '[MAIN]:WINDOW:OPEN': + return Object.assign({}, state, { + windowsOpen: uniq(state.windowsOpen.concat(action.payload.windowType)) + }); + case '[MAIN]:WINDOW:CLOSE': + return Object.assign({}, state, { + windowsOpen: state.windowsOpen.filter(w => { + return w !== action.payload.windowType; + }) + }); + case '[MAIN]:WINDOWS:INIT_FINISH': + return Object.assign({}, state, { windowsInit: true }); + case '[MAIN]:GENERIC_WINDOW:REUSE': + return Object.assign({}, state, { + genericWindowActingType: action.payload.actingType, + windowsOpen: state.windowsOpen.concat('generic') + }); + case '[MAIN]:GENERIC_WINDOW:RESET': + return Object.assign({}, state, { + genericWindowActingType: '', + windowsOpen: state.windowsOpen.filter(i => i !== 'generic') + }); + default: + return state; + } +}; + +export default ui; diff --git a/modules/db.js b/modules/db.js new file mode 100644 index 0000000..3734365 --- /dev/null +++ b/modules/db.js @@ -0,0 +1,69 @@ +const fs = require('fs'); +const Q = require('bluebird'); +const Loki = require('lokijs'); +const Settings = require('./settings'); +const log = require('./utils/logger').create('Db'); + +let db; + +exports.init = () => { + const filePath = Settings.dbFilePath; + + return Q.try(() => { + // if db file doesn't exist then create it + try { + log.debug(`Check that db exists and it's writeable: ${filePath}`); + fs.accessSync(filePath, fs.R_OK | fs.W_OK); + return Q.resolve(); + } catch (err) { + log.info(`Creating db: ${filePath}`); + + const tempdb = new Loki(filePath, { + env: 'NODEJS', + autoload: false + }); + + return new Q.promisify(tempdb.saveDatabase, { context: tempdb })(); + } + }).then(() => { + log.info(`Loading db: ${filePath}`); + + return new Q((resolve, reject) => { + db = new Loki(filePath, { + env: 'NODEJS', + autosave: true, + autosaveInterval: 5000, + autoload: true, + autoloadCallback(err) { + if (err) { + log.error(err); + reject(new Error('Error instantiating db')); + } + resolve(); + } + }); + }); + }); +}; + +exports.getCollection = name => { + if (!db.getCollection(name)) { + db.addCollection(name, { + unique: ['_id'] + }); + } + + return db.getCollection(name); +}; + +exports.close = () => { + return new Q((resolve, reject) => { + db.close(err => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); +}; diff --git a/modules/dbSync.js b/modules/dbSync.js new file mode 100644 index 0000000..7420a7e --- /dev/null +++ b/modules/dbSync.js @@ -0,0 +1,194 @@ +/** +@module dbSync +*/ +const { ipcMain, ipcRenderer } = require('electron'); + +/** + * Sync IPC calls received from given window into given db table. + * @param {Object} coll Db collection to save to. + */ +exports.initializeListeners = function() { + let log = require('./utils/logger').create('dbSync'), + db = require('./db'), + ipc = ipcMain; + + ipc.on('dbSync-add', (event, args) => { + let collName = args.collName, + coll = db.getCollection(`UI_${collName}`); + + log.trace('dbSync-add', collName, args._id); + + const _id = args._id; + + if (!coll.by('_id', _id)) { + args.fields._id = _id; + coll.insert(args.fields); + } + }); + + ipc.on('dbSync-changed', (event, args) => { + let collName = args.collName, + coll = db.getCollection(`UI_${collName}`); + + log.trace('dbSync-changed', collName, args._id); + + const _id = args._id; + const item = coll.by('_id', _id); + + if (item) { + for (const k in args.fields) { + if ({}.hasOwnProperty.call(args.fields, k)) { + item[k] = args.fields[k]; + } + } + + coll.update(item); + } else { + log.error('Item not found in db', _id); + } + }); + + ipc.on('dbSync-removed', (event, args) => { + let collName = args.collName, + coll = db.getCollection(`UI_${collName}`); + + log.trace('dbSync-removed', collName, args._id); + + const _id = args._id; + const item = coll.by('_id', _id); + + if (item) { + coll.remove(item); + } else { + log.error('Item not found in db', _id); + } + }); + + // Get all data (synchronous) + ipc.on('dbSync-reloadSync', (event, args) => { + let collName = args.collName, + coll = db.getCollection(`UI_${collName}`), + docs = coll.find(); + + log.debug('dbSync-reloadSync, no. of docs:', collName, docs.length); + + docs = docs.map(doc => { + const ret = {}; + + for (const k in doc) { + if (k !== 'meta' && k !== '$loki') { + ret[k] = doc[k]; + } + } + + return ret; + }); + + event.returnValue = docs; + }); +}; + +const syncDataFromBackend = function(coll) { + const ipc = ipcRenderer; + + const collName = coll._name; + + console.debug('Load collection data from backend: ', collName); + + return new Promise((resolve, reject) => { + const dataJson = ipc.sendSync('dbSync-reloadSync', { + collName + }); + + try { + let done = 0; + + coll.remove({}); + + if (!dataJson.length) { + resolve(); + } + + // we do inserts slowly, to avoid race conditions when it comes + // to updating the UI + dataJson.forEach(record => { + Tracker.afterFlush(() => { + try { + // On Meteor startup if a record contains a redirect to about:blank + // page, the application process crashes. + if ( + _.isString(record.redirect) && + record.redirect.indexOf('//about:blank') > -1 + ) { + record.redirect = null; + } + + if (record._id) { + coll.upsert(record._id, record); + } else { + coll.insert(record); + } + } catch (err) { + console.error(err.toString()); + } + + done++; + + if (done >= dataJson.length) { + resolve(); + } + }); + }); + } catch (err) { + reject(err); + } + }); +}; +exports.syncDataFromBackend = syncDataFromBackend; + +exports.frontendSyncInit = function(coll) { + let ipc = ipcRenderer, + syncDoneResolver; + + const collName = coll._name; + + coll.onceSynced = new Promise((resolve, reject) => { + syncDoneResolver = resolve; + }); + + syncDataFromBackend(coll) + .catch(err => { + console.error(err.toString()); + }) + .then(() => { + // start watching for changes + coll.find().observeChanges({ + added(id, fields) { + ipc.send('dbSync-add', { + collName, + _id: id, + fields + }); + }, + changed(id, fields) { + ipc.send('dbSync-changed', { + collName, + _id: id, + fields + }); + }, + removed(id) { + ipc.send('dbSync-removed', { + collName, + _id: id + }); + } + }); + + console.debug('Sync collection data to backend started: ', collName); + + syncDoneResolver(); + }); + + return coll; +}; diff --git a/modules/ethereumNode.js b/modules/ethereumNode.js new file mode 100644 index 0000000..ef65e4a --- /dev/null +++ b/modules/ethereumNode.js @@ -0,0 +1,594 @@ +const _ = global._; +const fs = require('fs'); +const Q = require('bluebird'); +const spawn = require('child_process').spawn; +const { dialog } = require('electron'); +const Windows = require('./windows.js'); +const Settings = require('./settings'); +const logRotate = require('log-rotate'); +const path = require('path'); +const EventEmitter = require('events').EventEmitter; +const Sockets = require('./socketManager'); +const ClientBinaryManager = require('./clientBinaryManager'); + +import logger from './utils/logger'; +const ethereumNodeLog = logger.create('EthereumNode'); + +const DEFAULT_NODE_TYPE = 'geth'; +const DEFAULT_NETWORK = 'main'; +const DEFAULT_SYNCMODE = 'fast'; + +const UNABLE_TO_BIND_PORT_ERROR = 'unableToBindPort'; +const NODE_START_WAIT_MS = 3000; + +const STATES = { + STARTING: 0 /* Node about to be started */, + STARTED: 1 /* Node started */, + CONNECTED: 2 /* IPC connected - all ready */, + STOPPING: 3 /* Node about to be stopped */, + STOPPED: 4 /* Node stopped */, + ERROR: -1 /* Unexpected error */ +}; + +/** + * Etheruem nodes manager. + */ +class EthereumNode extends EventEmitter { + constructor() { + super(); + + this.STATES = STATES; + + this._loadDefaults(); + + this._node = null; + this._type = null; + this._network = null; + + this._socket = Sockets.get('node-ipc', Settings.rpcMode); + + this.on('data', _.bind(this._logNodeData, this)); + } + + get isOwnNode() { + return !!this._node; + } + + get isExternalNode() { + return !this._node; + } + + get isIpcConnected() { + return this._socket.isConnected; + } + + get type() { + return this.isOwnNode ? this._type : null; + } + + get network() { + return this.isOwnNode ? this._network : null; + } + + get syncMode() { + return this._syncMode; + } + + get isEth() { + return this._type === 'eth'; + } + + get isGeth() { + return this._type === 'geth'; + } + + get isMainNetwork() { + return this.network === 'main'; + } + + get isTestNetwork() { + return this.network === 'test'; + } + + get isRinkebyNetwork() { + return this.network === 'rinkeby'; + } + + get isDevNetwork() { + return this.network === 'dev'; + } + + get isLightMode() { + return this._syncMode === 'fast'; + } + + get state() { + return this._state; + } + + get stateAsText() { + switch (this._state) { + case STATES.STARTING: + return 'starting'; + case STATES.STARTED: + return 'started'; + case STATES.CONNECTED: + return 'connected'; + case STATES.STOPPING: + return 'stopping'; + case STATES.STOPPED: + return 'stopped'; + case STATES.ERROR: + return 'error'; + default: + return false; + } + } + + set state(newState) { + this._state = newState; + + this.emit('state', this.state, this.stateAsText); + } + + get lastError() { + return this._lastErr; + } + + set lastError(err) { + this._lastErr = err; + } + + /** + * This method should always be called first to initialise the connection. + * @return {Promise} + */ + init() { + return this._socket + .connect(Settings.rpcConnectConfig) + .then(() => { + this.state = STATES.CONNECTED; + + this.emit('runningNodeFound'); + }) + .catch(() => { + ethereumNodeLog.warn( + "Failed to connect to node. Maybe it's not running so let's start our own..." + ); + + ethereumNodeLog.info(`Node type: ${this.defaultNodeType}`); + ethereumNodeLog.info(`Network: ${this.defaultNetwork}`); + ethereumNodeLog.info(`SyncMode: ${this.defaultSyncMode}`); + + // if not, start node yourself + return this._start( + this.defaultNodeType, + this.defaultNetwork, + this.defaultSyncMode + ).catch(err => { + ethereumNodeLog.error('Failed to start node', err); + throw err; + }); + }); + } + + restart(newType, newNetwork, syncMode) { + return Q.try(() => { + if (!this.isOwnNode) { + throw new Error('Cannot restart node since it was started externally'); + } + + ethereumNodeLog.info('Restart node', newType, newNetwork); + + return this.stop() + .then(() => Windows.loading.show()) + .then(() => + this._start( + newType || this.type, + newNetwork || this.network, + syncMode || this.syncMode + ) + ) + .then(() => Windows.loading.hide()) + .catch(err => { + ethereumNodeLog.error('Error restarting node', err); + throw err; + }); + }); + } + + /** + * Stop node. + * + * @return {Promise} + */ + stop() { + if (!this._stopPromise) { + return new Q(resolve => { + if (!this._node) { + return resolve(); + } + + this.state = STATES.STOPPING; + + ethereumNodeLog.info( + `Stopping existing node: ${this._type} ${this._network}` + ); + + this._node.stderr.removeAllListeners('data'); + this._node.stdout.removeAllListeners('data'); + this._node.stdin.removeAllListeners('error'); + this._node.removeAllListeners('error'); + this._node.removeAllListeners('exit'); + + this._node.kill('SIGINT'); + + // after some time just kill it if not already done so + const killTimeout = setTimeout(() => { + if (this._node) { + this._node.kill('SIGKILL'); + } + }, 8000 /* 8 seconds */); + + this._node.once('close', () => { + clearTimeout(killTimeout); + + this._node = null; + + resolve(); + }); + }).then(() => { + this.state = STATES.STOPPED; + this._stopPromise = null; + }); + } + ethereumNodeLog.debug( + 'Disconnection already in progress, returning Promise.' + ); + return this._stopPromise; + } + + /** + * Send Web3 command to socket. + * @param {String} method Method name + * @param {Array} [params] Method arguments + * @return {Promise} resolves to result or error. + */ + send(method, params) { + return this._socket.send({ + method, + params + }); + } + + /** + * Start an ethereum node. + * @param {String} nodeType geth, eth, etc + * @param {String} network network id + * @return {Promise} + */ + _start(nodeType, network, syncMode) { + ethereumNodeLog.info(`Start node: ${nodeType} ${network} ${syncMode}`); + + const isTestNet = network === 'test'; + + if (isTestNet) { + ethereumNodeLog.debug('Node will connect to the test network'); + } + + return this.stop() + .then(() => { + return this.__startNode(nodeType, network, syncMode).catch(err => { + ethereumNodeLog.error('Failed to start node', err); + + this._showNodeErrorDialog(nodeType, network); + + throw err; + }); + }) + .then(proc => { + ethereumNodeLog.info( + `Started node successfully: ${nodeType} ${network} ${syncMode}` + ); + + this._node = proc; + this.state = STATES.STARTED; + + Settings.saveUserData('node', this._type); + Settings.saveUserData('network', this._network); + Settings.saveUserData('syncmode', this._syncMode); + + return this._socket + .connect(Settings.rpcConnectConfig, { + timeout: 30000 /* 30s */ + }) + .then(() => { + this.state = STATES.CONNECTED; + }) + .catch(err => { + ethereumNodeLog.error('Failed to connect to node', err); + + if (err.toString().indexOf('timeout') >= 0) { + this.emit('nodeConnectionTimeout'); + } + + this._showNodeErrorDialog(nodeType, network); + + throw err; + }); + }) + .catch(err => { + // set before updating state so that state change event observers + // can pick up on this + this.lastError = err.tag; + this.state = STATES.ERROR; + + // if unable to start eth node then write geth to defaults + if (nodeType === 'eth') { + Settings.saveUserData('node', 'geth'); + } + + throw err; + }); + } + + /** + * @return {Promise} + */ + __startNode(nodeType, network, syncMode) { + this.state = STATES.STARTING; + + this._network = network; + this._type = nodeType; + this._syncMode = syncMode; + + const client = ClientBinaryManager.getClient(nodeType); + let binPath; + + if (client) { + binPath = client.binPath; + } else { + throw new Error(`Node "${nodeType}" binPath is not available.`); + } + + ethereumNodeLog.info(`Start node using ${binPath}`); + + return new Q((resolve, reject) => { + this.__startProcess(nodeType, network, binPath, syncMode).then( + resolve, + reject + ); + }); + } + + /** + * @return {Promise} + */ + __startProcess(nodeType, network, binPath, _syncMode) { + let syncMode = _syncMode; + if (nodeType === 'geth' && !syncMode) { + syncMode = DEFAULT_SYNCMODE; + } + + return new Q((resolve, reject) => { + ethereumNodeLog.trace('Rotate log file'); + + logRotate( + path.join(Settings.userDataPath, 'logs', 'all.log'), + { count: 5 }, + error => { + if (error) { + ethereumNodeLog.error('Log rotation problems', error); + return reject(error); + } + } + ); + + logRotate( + path.join( + Settings.userDataPath, + 'logs', + 'category', + 'ethereum_node.log' + ), + { count: 5 }, + error => { + if (error) { + ethereumNodeLog.error('Log rotation problems', error); + return reject(error); + } + } + ); + + let args; + + switch (network) { + // Starts Ropsten network + case 'test': + args = [ + '--testnet', + '--syncmode', + syncMode, + '--cache', + process.arch === 'x64' ? '1024' : '512', + '--ipcpath', + Settings.rpcIpcPath + ]; + break; + + // Starts Rinkeby network + case 'rinkeby': + args = [ + '--rinkeby', + '--syncmode', + syncMode, + '--cache', + process.arch === 'x64' ? '1024' : '512', + '--ipcpath', + Settings.rpcIpcPath + ]; + break; + + // Starts local network + case 'dev': + args = [ + '--dev', + '--minerthreads', + '1', + '--ipcpath', + Settings.rpcIpcPath + ]; + break; + + // Starts Main net + default: + args = + nodeType === 'geth' + ? [ + '--syncmode', + syncMode, + '--gcmode', + 'archive', + '--cache', + process.arch === 'x64' ? '1024' : '512' + ] + : ['--unsafe-transactions']; + } + + const nodeOptions = Settings.nodeOptions; + + if (nodeOptions && nodeOptions.length) { + ethereumNodeLog.debug('Custom node options', nodeOptions); + + args = args.concat(nodeOptions); + } + + ethereumNodeLog.trace('Spawn', binPath, args); + + const proc = spawn(binPath, args); + + proc.once('error', error => { + if (this.state === STATES.STARTING) { + this.state = STATES.ERROR; + + ethereumNodeLog.info('Node startup error'); + + // TODO: detect this properly + // this.emit('nodeBinaryNotFound'); + + reject(error); + } + }); + + proc.stdout.on('data', data => { + ethereumNodeLog.trace('Got stdout data', data.toString()); + this.emit('data', data); + }); + + proc.stderr.on('data', data => { + ethereumNodeLog.trace('Got stderr data', data.toString()); + ethereumNodeLog.info(data.toString()); // TODO: This should be ethereumNodeLog.error(), but not sure why regular stdout data is coming in through stderror + this.emit('data', data); + }); + + // when data is first received + this.once('data', () => { + /* + We wait a short while before marking startup as successful + because we may want to parse the initial node output for + errors, etc (see geth port-binding error above) + */ + setTimeout(() => { + if (STATES.STARTING === this.state) { + ethereumNodeLog.info( + `${NODE_START_WAIT_MS}ms elapsed, assuming node started up successfully` + ); + resolve(proc); + } + }, NODE_START_WAIT_MS); + }); + }); + } + + _showNodeErrorDialog(nodeType, network) { + let log = path.join(Settings.userDataPath, 'logs', 'all.log'); + + if (log) { + log = `...${log.slice(-1000)}`; + } else { + log = global.i18n.t('mist.errors.nodeStartup'); + } + + // add node type + log = + `Node type: ${nodeType}\n` + + `Network: ${network}\n` + + `Platform: ${process.platform} (Architecture ${process.arch})\n\n${log}`; + + dialog.showMessageBox( + { + type: 'error', + buttons: ['OK'], + message: global.i18n.t('mist.errors.nodeConnect'), + detail: log + }, + () => {} + ); + } + + _logNodeData(data) { + const cleanData = data.toString().replace(/[\r\n]+/, ''); + const nodeType = (this.type || 'node').toUpperCase(); + + ethereumNodeLog.trace(`${nodeType}: ${cleanData}`); + + if (!/^-*$/.test(cleanData) && !_.isEmpty(cleanData)) { + this.emit('nodeLog', cleanData); + } + + // check for geth startup errors + if (STATES.STARTING === this.state) { + const dataStr = data.toString().toLowerCase(); + if (nodeType === 'geth') { + if (dataStr.indexOf('fatal: error') >= 0) { + const error = new Error(`Geth error: ${dataStr}`); + + if (dataStr.indexOf('bind') >= 0) { + error.tag = UNABLE_TO_BIND_PORT_ERROR; + } + + ethereumNodeLog.error(error); + return reject(error); + } + } + } + } + + _loadDefaults() { + ethereumNodeLog.trace('Load defaults'); + + this.defaultNodeType = + Settings.nodeType || Settings.loadUserData('node') || DEFAULT_NODE_TYPE; + this.defaultNetwork = + Settings.network || Settings.loadUserData('network') || DEFAULT_NETWORK; + this.defaultSyncMode = + Settings.syncmode || + Settings.loadUserData('syncmode') || + DEFAULT_SYNCMODE; + + ethereumNodeLog.info( + Settings.syncmode, + Settings.loadUserData('syncmode'), + DEFAULT_SYNCMODE + ); + ethereumNodeLog.info( + `Defaults loaded: ${this.defaultNodeType} ${this.defaultNetwork} ${ + this.defaultSyncMode + }` + ); + } +} + +EthereumNode.STARTING = 0; + +module.exports = new EthereumNode(); diff --git a/modules/i18n.js b/modules/i18n.js new file mode 100644 index 0000000..d3fc4b7 --- /dev/null +++ b/modules/i18n.js @@ -0,0 +1,53 @@ +/** +The i18n module, loads the language files and initializes i18next + +@module i18n +*/ +const fs = require('fs'); +const i18n = require('i18next'); + +let i18nConf = fs.readFileSync(`${__dirname}/../interface/project-tap.i18n`); +i18nConf = JSON.parse(i18nConf); + +const resources = { + dev: { translation: require('../interface/i18n/mist.en.i18n.json') } +}; + +// add supported languages +i18nConf.supported_languages.forEach(lang => { + resources[lang] = { + translation: require(`../interface/i18n/mist.${lang}.i18n.json`) + }; +}); + +/** + * Given a language code, get best matched code from supported languages. + * + * > getBestMatchedLangCode('en-US') + * 'en' + * > getBestMatchedLangCode('zh-TW') + * 'zh-TW' + * > getBestMatchedLangCode('no-such-code') + * 'en' + */ +i18n.getBestMatchedLangCode = langCode => { + const codeList = Object.keys(resources); + let bestMatchedCode = langCode; + if (codeList.indexOf(langCode) === -1) { + if (codeList.indexOf(langCode.substr(0, 2)) > -1) { + bestMatchedCode = langCode.substr(0, 2); + } else { + bestMatchedCode = 'en'; + } + } + return bestMatchedCode; +}; + +// init i18n +i18n.init({ + lng: global.language || 'en', + resources, + interpolation: { prefix: '__', suffix: '__' } +}); + +module.exports = i18n; diff --git a/modules/ipc/ipcProviderBackend.js b/modules/ipc/ipcProviderBackend.js new file mode 100644 index 0000000..5989c1a --- /dev/null +++ b/modules/ipc/ipcProviderBackend.js @@ -0,0 +1,485 @@ +/** +The IPC provider backend filter and tunnel all incoming request to the ethereum node. + +@module ipcProviderBackend +*/ + +const _ = global._; +const Q = require('bluebird'); +const { ipcMain: ipc } = require('electron'); +const fs = require('fs'); +const path = require('path'); + +const log = require('../utils/logger').create('ipcProviderBackend'); +const Sockets = require('../socketManager'); +const Settings = require('../settings'); +const ethereumNode = require('../ethereumNode'); + +const ERRORS = { + INVALID_PAYLOAD: { + code: -32600, + message: + "Payload, or some of its content properties are invalid. Please check if they are valid HEX with '0x' prefix." + }, + METHOD_DENIED: { code: -32601, message: 'Method __method__ not allowed.' }, + METHOD_TIMEOUT: { + code: -32603, + message: 'Request timed out for method __method__.' + }, + TX_DENIED: { code: -32603, message: 'Transaction denied' }, + BATCH_TX_DENIED: { + code: -32603, + message: + 'Transactions denied, sendTransaction is not allowed in batch requests.' + }, + BATCH_COMPILE_DENIED: { + code: -32603, + message: + 'Compilation denied, compileSolidity is not allowed in batch requests.' + } +}; + +/** + * IPC provider backend. + */ +class IpcProviderBackend { + constructor() { + this._connections = {}; + + this.ERRORS = ERRORS; + + ethereumNode.on('state', _.bind(this._onNodeStateChanged, this)); + + ipc.on('ipcProvider-create', _.bind(this._getOrCreateConnection, this)); + ipc.on('ipcProvider-destroy', _.bind(this._destroyConnection, this)); + ipc.on('ipcProvider-write', _.bind(this._sendRequest, this, false)); + ipc.on('ipcProvider-writeSync', _.bind(this._sendRequest, this, true)); + + this._connectionPromise = {}; + + // dynamically load in method processors + const processors = fs.readdirSync(path.join(__dirname, 'methods')); + + // get response processors + this._processors = {}; + processors.forEach(p => { + const name = path.basename(p, '.js'); + + const PClass = require(path.join(__dirname, 'methods', p)); + + this._processors[name] = new PClass(name, this); + }); + + log.trace('Loaded processors', _.keys(this._processors)); + + store.dispatch({ type: '[MAIN]:IPC_PROVIDER_BACKEND:INIT' }); + } + + /** + * Get/create new connection to node. + * @return {Promise} + */ + _getOrCreateConnection(event) { + const owner = event.sender; + const ownerId = owner.id; + + let socket; + + return Q.try(() => { + // already got? + if (this._connections[ownerId]) { + socket = this._connections[ownerId].socket; + } else { + log.debug(`Create new socket connection, id=${ownerId}`); + + socket = Sockets.get(ownerId, Settings.rpcMode); + } + }) + .then(() => { + if (!this._connections[ownerId]) { + // save to collection + this._connections[ownerId] = { + id: ownerId, + owner, + socket + }; + + // if something goes wrong destroy the socket + ['error', 'timeout', 'end'].forEach(ev => { + socket.on(ev, data => { + log.debug( + `Destroy socket connection due to event: ${ev}, id=${ownerId}` + ); + + socket.destroy().finally(() => { + if (!owner.isDestroyed()) { + owner.send(`ipcProvider-${ev}`, JSON.stringify(data)); + } + }); + + delete this._connections[ownerId]; + Sockets.remove(ownerId); + }); + }); + + socket.on('connect', data => { + if (!owner.isDestroyed()) { + owner.send('ipcProvider-connect', JSON.stringify(data)); + } + }); + + // pass notifications back up the chain + socket.on('data-notification', data => { + log.trace('Notification received', ownerId, data); + + if (data.error) { + data = this._makeErrorResponsePayload(data, data); + } else { + data = this._makeResponsePayload(data, data); + } + + if (!owner.isDestroyed()) { + owner.send('ipcProvider-data', JSON.stringify(data)); + } + }); + } + }) + .then(() => { + if (!socket.isConnected) { + // since we may enter this function multiple times for the same + // event source's IPC we don't want to repeat the connection + // process each time - so let's track things in a promise + if (!this._connectionPromise[ownerId]) { + this._connectionPromise[ownerId] = Q.try(() => { + log.debug(`Connecting socket ${ownerId}`); + + // wait for node to connect first. + if (ethereumNode.state !== ethereumNode.STATES.CONNECTED) { + return new Q((resolve, reject) => { + const onStateChange = newState => { + if (ethereumNode.STATES.CONNECTED === newState) { + ethereumNode.removeListener('state', onStateChange); + + log.debug( + `Ethereum node connected, resume connecting socket ${ownerId}` + ); + + resolve(); + } + }; + + ethereumNode.on('state', onStateChange); + }); + } + }) + .then(() => { + return socket.connect(Settings.rpcConnectConfig, { + timeout: 5000 + }); + }) + .then(() => { + log.debug(`Socket connected, id=${ownerId}`); + }) + .finally(() => { + delete this._connectionPromise[ownerId]; + }); + } + + return this._connectionPromise[ownerId]; + } + }) + .then(() => { + if (!owner.isDestroyed()) { + owner.send('ipcProvider-setWritable', true); + } + + return this._connections[ownerId]; + }); + } + + /** + * Handle IPC call to destroy a connection. + */ + _destroyConnection(event) { + const ownerId = event.sender.id; + + if (this._connections[ownerId]) { + log.debug('Destroy socket connection', ownerId); + + this._connections[ownerId].owner.send('ipcProvider-setWritable', false); + + this._connections[ownerId].socket.destroy(); + delete this._connections[ownerId]; + Sockets.remove(ownerId); + } + } + + /** + * Handler for when Ethereum node state changes. + * + * Auto-reconnect sockets when ethereum node state changes + * + * @param {String} state The new state. + */ + _onNodeStateChanged(state) { + switch (state) { // eslint-disable-line default-case + // stop syncing when node about to be stopped + case ethereumNode.STATES.STOPPING: + log.info('EtherCore node stopping, disconnecting sockets'); + + Q.all( + _.map(this._connections, item => { + if (item.socket.isConnected) { + return item.socket.disconnect().then(() => { + log.debug( + `Tell owner ${item.id} that socket is not currently writeable` + ); + + item.owner.send('ipcProvider-setWritable', false); + }); + } + return Q.resolve(); + }) + ).catch(err => { + log.error('Error disconnecting sockets', err); + }); + + break; + } + } + + /** + * Handle IPC call to send a request. + * @param {Boolean} isSync whether request is sync. + * @param {Object} event IPC event. + * @param {String} payload request payload. + */ + _sendRequest(isSync, event, payload) { + const ownerId = event.sender.id; + + log.trace('sendRequest', isSync ? 'sync' : 'async', ownerId, payload); + + const originalPayloadStr = payload; + + return Q.try(() => { + // overwrite playload var with parsed version + payload = JSON.parse(originalPayloadStr); + + return this._getOrCreateConnection(event); + }) + .then(conn => { + if (!conn.socket.isConnected) { + log.trace('Socket not connected.'); + + throw this.ERRORS.METHOD_TIMEOUT; + } + + // reparse original string (so that we don't modify input payload) + const finalPayload = JSON.parse(originalPayloadStr); + + // is batch? + const isBatch = _.isArray(finalPayload), + finalPayloadList = isBatch ? finalPayload : [finalPayload]; + + // sanitize each and every request payload + _.each(finalPayloadList, p => { + const processor = this._processors[p.method] + ? this._processors[p.method] + : this._processors.base; + + processor.sanitizeRequestPayload(conn, p, isBatch); + }); + + // if a single payload and has an error then throw it + if (!isBatch && finalPayload.error) { + throw finalPayload.error; + } + + // get non-error payloads + const nonErrorPayloads = _.filter(finalPayloadList, p => !p.error); + + // execute non-error payloads + return Q.try(() => { + if (nonErrorPayloads.length) { + // if single payload check if we have special processor for it + // if not then use base generic processor + const processor = this._processors[finalPayload.method] + ? this._processors[finalPayload.method] + : this._processors.base; + + return processor.exec( + conn, + isBatch ? nonErrorPayloads : nonErrorPayloads[0] + ); + } else { + return []; + } + }).then(ret => { + log.trace('Got result', ret); + + let finalResult = []; + + // collate results + _.each(finalPayloadList, p => { + if (p.error) { + finalResult.push(p); + } else { + p = _.extend({}, p, isBatch ? ret.shift() : ret); + + const processor = this._processors[p.method] + ? this._processors[p.method] + : this._processors.base; + + // sanitize response payload + processor.sanitizeResponsePayload(conn, p, isBatch); + + finalResult.push(p); + } + }); + + // extract single payload result + if (!isBatch) { + finalResult = finalResult.pop(); + + // check if it's an error + if (finalResult.error) { + throw finalResult.error; + } + } + + return finalResult; + }); + }) + .then(result => { + log.trace('Got result', result); + + return this._makeResponsePayload(payload, result); + }) + .catch(err => { + log.error('Send request failed', err); + + err = this._makeErrorResponsePayload(payload || {}, { + message: typeof err === 'string' ? err : err.message, + code: err.code + }); + + return err; + }) + .then(returnValue => { + returnValue = JSON.stringify(returnValue); + + log.trace('Return', ownerId, returnValue); + + if (isSync) { + event.returnValue = returnValue; + } else if (!event.sender.isDestroyed()) { + event.sender.send('ipcProvider-data', returnValue); + } + }); + } + + /** + Sanitize a single or batch request payload. + + This will modify the passed-in payload. + + @param {Object} conn The connection. + @param {Object|Array} payload The request payload. + */ + _sanitizeRequestPayload(conn, payload) { + if (_.isArray(payload)) { + _.each(payload, p => { + if (p.method === 'eth_sendTransaction') { + p.error = ERRORS.BATCH_TX_DENIED; + } else { + this._processors.base.sanitizePayload(conn, p); + } + }); + } else { + this._processors.base.sanitizePayload(conn, payload); + } + } + + /** + Make an error response payload + + @param {Object|Array} originalPayload Original payload + @param {Object} error Error result + */ + _makeErrorResponsePayload(originalPayload, error) { + const e = [].concat(originalPayload).map(item => { + const e = _.extend( + { + jsonrpc: '2.0' + }, + error + ); + + if (e.message) { + if (_.isArray(e.message)) { + e.message = e.message.pop(); + } + + e.error = { + code: e.code, + message: e.message.replace(/'[a-z_]*'/i, `'${item.method}'`) + }; + + delete e.code; + delete e.message; + } + + // delete stuff leftover from request + delete e.params; + delete e.method; + + e.id = item.id; + + return e; + }); + + return _.isArray(originalPayload) ? e : e[0]; + } + + /** + Make a response payload. + + @param {Object|Array} originalPayload Original payload + @param {Object|Array} value Response results. + + @method makeReturnValue + */ + _makeResponsePayload(originalPayload, value) { + const finalValue = _.isArray(originalPayload) ? value : [value]; + + const allResults = [].concat(originalPayload).map((item, idx) => { + const finalResult = finalValue[idx]; + + let ret; + + // handle error result + if (finalResult.error) { + ret = this._makeErrorResponsePayload(item, finalResult.error); + } else { + ret = _.extend({}, item, { + result: finalResult.result + }); + } + + if (item.id) { + delete ret.params; + delete ret.method; + } + + ret.jsonrpc = '2.0'; + + return ret; + }); + + return _.isArray(originalPayload) ? allResults : allResults[0]; + } +} + +exports.init = () => { + return new IpcProviderBackend(); +}; diff --git a/modules/ipc/ipcProviderWrapper.js b/modules/ipc/ipcProviderWrapper.js new file mode 100644 index 0000000..1deb7b9 --- /dev/null +++ b/modules/ipc/ipcProviderWrapper.js @@ -0,0 +1,121 @@ +/** +@module MistUI +*/ + +/** +The IPC provider wrapper to communicate to the backend + +@class ipcProviderWrapper +@constructor +*/ + +const { ipcRenderer } = require('electron'); + +/** +Gets the writable property. + +@method on('ipcProvider-setWritable') +*/ +ipcRenderer.on('ipcProvider-setWritable', (e, writable) => { + // console.debug('ipcProvider-setWritable', writable); + + ipcProviderWrapper.writable = writable; +}); + +const ipcProviderWrapper = { + writable: false, + + /** + Connects the IPC on the backend to the geth node + + Note: web3.isConnected will always return true, as otherwise race conditions can occour, + letting it look like youre not connected via IPC. + + @method connect + */ + connect(path) { + // console.debug('ipcProviderWrapper: connect'); + + ipcRenderer.send('ipcProvider-create', path); + + return this; + }, + /** + Returns data from the IPC through the backend + + @method on + @param {String} name `connect`, `error`, `end`, `timeout` or `data` + @param {Funciton} callback + */ + on(name, callback) { + // console.debug('ipcProviderWrapper: add listener', name); + + ipcRenderer.on(`ipcProvider-${name}`, (e, result) => { + callback(result); + }); + }, + /** + Returns data from the IPC through the backend + + @method once + @param {String} name `connect`, `error`, `end`, `timeout` or `data` + @param {Funciton} callback + */ + once(name, callback) { + // console.debug('ipcProviderWrapper: add listener', name); + + ipcRenderer.once(`ipcProvider-${name}`, (e, result) => { + callback(result); + }); + }, + /** + Removes listener + + @method removeListener + */ + removeListener(name, callback) { + // console.debug('ipcProviderWrapper: remove listener', name); + + ipcRenderer.removeListener(`ipcProvider-${name}`, callback); + }, + + /** + Removes all listeners + + @method removeAllListeners + */ + removeAllListeners(name) { + // console.debug('ipcProviderWrapper: remove all listeners', name); + + if (name) { + ipcRenderer.removeAllListeners(`ipcProvider-${name}`); + } else { + ipcRenderer.removeAllListeners('ipcProvider-error'); + ipcRenderer.removeAllListeners('ipcProvider-end'); + ipcRenderer.removeAllListeners('ipcProvider-timeout'); + ipcRenderer.removeAllListeners('ipcProvider-connect'); + } + }, + /** + Write to the IPC connection through the backend + + @method write + */ + write(payload) { + // console.debug('ipcProviderWrapper: write payload'); + + ipcRenderer.send('ipcProvider-write', payload); + }, + /** + Write synchronous to the IPC connection through the backend + + @method writeSync + */ + writeSync(payload) { + // console.debug('ipcProviderWrapper: write payload (sync)'); + + return ipcRenderer.sendSync('ipcProvider-writeSync', payload); + } +}; + +module.exports = ipcProviderWrapper; diff --git a/modules/ipc/methods/base.js b/modules/ipc/methods/base.js new file mode 100644 index 0000000..e4cdfc4 --- /dev/null +++ b/modules/ipc/methods/base.js @@ -0,0 +1,103 @@ +const _ = global._; +const Q = require('bluebird'); + +const log = require('../../utils/logger').create('method'); +const Windows = require('../../windows'); +const db = require('../../db'); + +/** + * Process a request. + * + * This is the base class for all specialized request processors. + */ +module.exports = class BaseProcessor { + constructor(name, ipcProviderBackend) { + this._log = log.create(name); + this._ipcProviderBackend = ipcProviderBackend; + this.ERRORS = this._ipcProviderBackend.ERRORS; + } + + /** + * Execute given request. + * @param {Object} conn IPCProviderBackend connection data. + * @param {Object|Array} payload payload + * @return {Promise} + */ + async exec(conn, payload) { + this._log.trace('Execute request', payload); + + const ret = await conn.socket.send(payload, { + fullResult: true + }); + + return ret.result; + } + + _isAdminConnection(conn) { + // main window or popupwindows - always allow requests + const wnd = Windows.getById(conn.id); + const tab = db.getCollection('UI_tabs').findOne({ webviewId: conn.id }); + + return ( + (wnd && (wnd.type === 'main' || wnd.isPopup)) || + (tab && _.get(tab, 'permissions.admin') === true) + ); + } + + /** + Sanitize a request payload. + + This may modify the input payload object. + + @param {Object} conn The connection. + @param {Object} payload The request payload. + @param {Boolean} isPartOfABatch Whether it's part of a batch payload. + */ + sanitizeRequestPayload(conn, payload, isPartOfABatch) { + this._log.trace('Sanitize request payload', payload); + + this._sanitizeRequestResponsePayload(conn, payload, isPartOfABatch); + } + + /** + Sanitize a response payload. + + This may modify the input payload object. + + @param {Object} conn The connection. + @param {Object} payload The request payload. + @param {Boolean} isPartOfABatch Whether it's part of a batch payload. + */ + sanitizeResponsePayload(conn, payload, isPartOfABatch) { + this._log.trace('Sanitize response payload', payload); + + this._sanitizeRequestResponsePayload(conn, payload, isPartOfABatch); + } + + /** + Sanitize a request or response payload. + + This may modify the input payload object. + + @param {Object} conn The connection. + @param {Object} payload The request payload. + @param {Boolean} isPartOfABatch Whether it's part of a batch payload. + */ + _sanitizeRequestResponsePayload(conn, payload, isPartOfABatch) { + if (!_.isObject(payload)) { + throw this.ERRORS.INVALID_PAYLOAD; + } + + if (this._isAdminConnection(conn)) { + return; + } + + // prevent dapps from acccesing admin endpoints + if (!/^eth_|^bzz_|^shh_|^net_|^web3_|^db_/.test(payload.method)) { + delete payload.result; + const err = _.clone(this.ERRORS.METHOD_DENIED); + err.message = err.message.replace('__method__', `"${payload.method}"`); + payload.error = err; + } + } +}; diff --git a/modules/ipc/methods/eth_accounts.js b/modules/ipc/methods/eth_accounts.js new file mode 100644 index 0000000..a1405af --- /dev/null +++ b/modules/ipc/methods/eth_accounts.js @@ -0,0 +1,31 @@ +const _ = global._; +const BaseProcessor = require('./base'); +const db = require('../../db'); + +/** + * Process method: eth_accounts + */ +module.exports = class extends BaseProcessor { + /** + * @override + */ + sanitizeResponsePayload(conn, payload, isPartOfABatch) { + this._log.trace('Sanitize eth_acconts', payload.result); + + // if not an admin connection then do a check + if (!this._isAdminConnection(conn)) { + const tab = db.getCollection('UI_tabs').findOne({ webviewId: conn.id }); + + if (_.get(tab, 'permissions.accounts')) { + payload.result = _.intersection( + payload.result, + tab.permissions.accounts + ); + } else { + payload.result = []; + } + } + + return super.sanitizeResponsePayload(conn, payload, isPartOfABatch); + } +}; diff --git a/modules/ipc/methods/eth_coinbase.js b/modules/ipc/methods/eth_coinbase.js new file mode 100644 index 0000000..a4508fb --- /dev/null +++ b/modules/ipc/methods/eth_coinbase.js @@ -0,0 +1,29 @@ +const _ = global._; +const BaseProcessor = require('./base'); +const db = require('../../db'); + +/** + * Process method: eth_coinbase + */ +module.exports = class extends BaseProcessor { + /** + * @override + */ + sanitizeResponsePayload(conn, payload, isPartOfABatch) { + this._log.trace('Sanitize account eth_coinbase', payload.result); + + // if not an admin connection then do a check + if (!this._isAdminConnection(conn)) { + const tab = db.getCollection('UI_tabs').findOne({ webviewId: conn.id }); + + if (_.get(tab, 'permissions.accounts')) { + payload.result = _.contains(tab.permissions.accounts, payload.result) + ? payload.result + : null; + } else { + payload.result = null; + } + } + return super.sanitizeResponsePayload(conn, payload, isPartOfABatch); + } +}; diff --git a/modules/ipc/methods/eth_compileSolidity.js b/modules/ipc/methods/eth_compileSolidity.js new file mode 100644 index 0000000..f4a59a3 --- /dev/null +++ b/modules/ipc/methods/eth_compileSolidity.js @@ -0,0 +1,50 @@ +const _ = global._; +const solc = require('solc'); +const Q = require('bluebird'); +const BaseProcessor = require('./base'); + +/** + * Process method: eth_compileSolidity + */ +module.exports = class extends BaseProcessor { + /** + * @override + */ + exec(conn, payload) { + return Q.try(() => { + this._log.debug('Compile solidity'); + + const output = solc.compile(payload.params[0], 1); // 1 activates the optimiser + + const finalResult = _.extend({}, payload); + + if (!output || output.errors) { + let msg = output ? output.errors : 'Compile error'; + + if (_.isArray(msg)) { + msg = msg.join(', '); + } + + finalResult.error = { + code: -32700, + message: msg + }; + } else { + finalResult.result = output.contracts; + } + + return finalResult; + }); + } + + /** + * @override + */ + sanitizeRequestPayload(conn, payload, isPartOfABatch) { + if (isPartOfABatch) { + throw this.ERRORS.BATCH_COMPILE_DENIED; + } + + return super.sanitizeRequestPayload(conn, payload, isPartOfABatch); + } +}; diff --git a/modules/ipc/methods/eth_getTransactionReceipt.js b/modules/ipc/methods/eth_getTransactionReceipt.js new file mode 100644 index 0000000..e4e5444 --- /dev/null +++ b/modules/ipc/methods/eth_getTransactionReceipt.js @@ -0,0 +1,70 @@ +const _ = global._; +const BaseProcessor = require('./base'); +const eth = require('ethereumjs-util'); + +/** + * Process method: eth_getTransactionReceipt + * Due to a geth's light client v1 bug, it does not return + * contractAddress value on the receipts. Let's fix that. + */ + +module.exports = class extends BaseProcessor { + sanitizeRequestPayload(conn, payload, isPartOfABatch) { + return super.sanitizeRequestPayload(conn, payload, isPartOfABatch); + } + + async exec(conn, payload) { + const txHash = payload.params[0]; + + // Sends regular eth_getTransactionReceipt request + const ret = await conn.socket.send(payload, { + fullResult: true + }); + + try { + // If that contains a contractAddress already, fine. + if (ret.result.result && ret.result.result.contractAddress != null) { + return ret.result; + } + + // 1. GET TRANSACTION from AND nonce VALUES + const transactionInfo = await conn.socket.send( + { + jsonrpc: '2.0', + id: _.uuid(), + method: 'eth_getTransactionByHash', + params: [txHash] + }, + { fullResult: true } + ); + + const fromAddress = transactionInfo.result.result.from; + const nonce = parseInt(transactionInfo.result.result.nonce, 16); + const possibleContractAddress = `0x${eth + .generateAddress(fromAddress, nonce) + .toString('hex')}`; + + // 2. GET CODE FROM ADDRESS + const contractCode = await conn.socket.send( + { + jsonrpc: '2.0', + id: _.uuid(), + method: 'eth_getCode', + params: [possibleContractAddress, 'latest'] + }, + { fullResult: true } + ); + + const contractCodeResult = contractCode.result.result; + + // 3. IF IT EXISTS, ASSIGN TO RETURN VALUE + if (contractCodeResult && contractCodeResult.length > 2) { + ret.result.result.contractAddress = possibleContractAddress; + } + } catch (e) { + console.warn('[WARN]', txHash, e); + return ret.result; + } + return ret.result; + } +}; diff --git a/modules/ipc/methods/eth_sendTransaction.js b/modules/ipc/methods/eth_sendTransaction.js new file mode 100644 index 0000000..f303098 --- /dev/null +++ b/modules/ipc/methods/eth_sendTransaction.js @@ -0,0 +1,95 @@ +const BaseProcessor = require('./base'); +const Windows = require('../../windows'); +const Q = require('bluebird'); +const { ipcMain: ipc } = require('electron'); +const BlurOverlay = require('../../blurOverlay'); + +/** + * Process method: eth_sendTransaction + */ +module.exports = class extends BaseProcessor { + /** + * @override + */ + sanitizeRequestPayload(conn, payload, isPartOfABatch) { + if (isPartOfABatch) { + throw this.ERRORS.BATCH_TX_DENIED; + } + + return super.sanitizeRequestPayload(conn, payload, isPartOfABatch); + } + + /** + * @override + */ + exec(conn, payload) { + return new Q((resolve, reject) => { + this._log.info('Ask user for password'); + + this._log.info(payload.params[0]); + + // validate data + try { + _.each(payload.params[0], (val, key) => { + // if doesn't have hex then leave + if (!_.isString(val)) { + throw this.ERRORS.INVALID_PAYLOAD; + } else { + // make sure all data is lowercase and has 0x + if (val) val = `0x${val.toLowerCase().replace(/^0x/, '')}`; + + if (val.substr(2).match(/[^0-9a-f]/gim)) { + throw this.ERRORS.INVALID_PAYLOAD; + } + } + + payload.params[0][key] = val; + }); + } catch (err) { + return reject(err); + } + + const modalWindow = Windows.createPopup('sendTransactionConfirmation', { + sendData: { uiAction_sendData: payload.params[0] } + }); + + BlurOverlay.enable(); + + modalWindow.on('hidden', () => { + BlurOverlay.disable(); + + // user cancelled? + if (!modalWindow.processed) { + reject(this.ERRORS.METHOD_DENIED); + } + }); + + ipc.once( + 'backendAction_unlockedAccountAndSentTransaction', + (ev, err, result) => { + if ( + Windows.getById(ev.sender.id) === modalWindow && + !modalWindow.isClosed + ) { + if (err || !result) { + this._log.debug('Confirmation error', err); + + reject(err || this.ERRORS.METHOD_DENIED); + } else { + this._log.info('Transaction sent', result); + + resolve(result); + } + + modalWindow.processed = true; + modalWindow.close(); + } + } + ); + }).then(result => { + return _.extend({}, payload, { + result + }); + }); + } +}; diff --git a/modules/ipcCommunicator.js b/modules/ipcCommunicator.js new file mode 100644 index 0000000..8e63608 --- /dev/null +++ b/modules/ipcCommunicator.js @@ -0,0 +1,290 @@ +/** +Window communication + +@module ipcCommunicator +*/ + +const _ = global._; +const fs = require('fs'); +const { app, ipcMain: ipc, shell, webContents } = require('electron'); +const Windows = require('./windows'); +const logger = require('./utils/logger'); +const appMenu = require('./menuItems'); +const Settings = require('./settings'); +const ethereumNode = require('./ethereumNode.js'); +const keyfileRecognizer = require('ethereum-keyfile-recognizer'); + +import { getLanguage } from './core/settings/actions'; + +const log = logger.create('ipcCommunicator'); + +require('./abi.js'); +/* + +// windows including webviews +windows = { + 23: { + type: 'requestWindow', + window: obj, + owner: 12 + }, + 12: { + type: 'webview' + window: obj + owner: null + } +} + +*/ + +// UI ACTIONS +ipc.on('backendAction_closeApp', () => { + app.quit(); +}); + +ipc.on('backendAction_openExternalUrl', (e, url) => { + shell.openExternal(url); +}); + +ipc.on('backendAction_closePopupWindow', e => { + const windowId = e.sender.id; + const senderWindow = Windows.getById(windowId); + + if (senderWindow) { + senderWindow.close(); + } +}); +ipc.on('backendAction_setWindowSize', (e, width, height) => { + const windowId = e.sender.id; + const senderWindow = Windows.getById(windowId); + + if (senderWindow) { + senderWindow.window.setSize(width, height); + senderWindow.window.center(); // ? + } +}); + +ipc.on('backendAction_windowCallback', (e, value1, value2, value3) => { + const windowId = e.sender.id; + const senderWindow = Windows.getById(windowId); + + if (senderWindow.callback) { + senderWindow.callback(value1, value2, value3); + } +}); + +ipc.on('backendAction_windowMessageToOwner', (e, error, value) => { + const windowId = e.sender.id; + const senderWindow = Windows.getById(windowId); + + // If msg is from a generic window, use the "actingType" instead of type + const senderWindowType = senderWindow.actingType || senderWindow.type; + + if (senderWindow.ownerId) { + const ownerWindow = Windows.getById(senderWindow.ownerId); + const mainWindow = Windows.getByType('main'); + + if (ownerWindow) { + ownerWindow.send( + 'uiAction_windowMessage', + senderWindowType, + error, + value + ); + } + + // send through the mainWindow to the webviews + if (mainWindow) { + mainWindow.send( + 'uiAction_windowMessage', + senderWindowType, + senderWindow.ownerId, + error, + value + ); + } + } +}); + +ipc.on('backendAction_getLanguage', e => { + store.dispatch(getLanguage(e)); +}); + +ipc.on('backendAction_stopWebviewNavigation', (e, id) => { + console.log('webcontent ID', id); + const webContent = webContents.fromId(id); + + if (webContent && !webContent.isDestroyed()) { + webContent.stop(); + } + + e.returnValue = true; +}); + +// check wallet file +ipc.on('backendAction_checkWalletFile', (e, path) => { + fs.readFile(path, 'utf8', (event, data) => { + try { + const keyfile = JSON.parse(data); + const result = keyfileRecognizer(keyfile); + /** result + * [ 'ethersale', undefined ] Ethersale keyfile + * [ 'web3', 3 ] web3 (v3) keyfile + * null no valid keyfile + */ + + const type = _.first(result); + + log.debug(`Importing ${type} account...`); + + if (type === 'ethersale') { + e.sender.send('uiAction_checkedWalletFile', null, 'presale'); + } else if (type === 'web3') { + e.sender.send('uiAction_checkedWalletFile', null, 'web3'); + + let keystorePath = Settings.userHomePath; + // eth + if (ethereumNode.isEth) { + if (process.platform === 'win32') { + keystorePath = `${Settings.appDataPath}\\Web3\\keys`; + } else { + keystorePath += '/.web3/keys'; + } + // geth + } else { + if (process.platform === 'darwin') + keystorePath += '/Library/EtherCore/keystore'; + + if ( + process.platform === 'freebsd' || + process.platform === 'linux' || + process.platform === 'sunos' + ) + keystorePath += '/.ethercore/keystore'; + + if (process.platform === 'win32') + keystorePath = `${Settings.appDataPath}\\EtherCore\\keystore`; + } + + if (!/^[0-9a-fA-F]{40}$/.test(keyfile.address)) { + throw new Error('Invalid Address format.'); + } + + fs.writeFile(`${keystorePath}/0x${keyfile.address}`, data, err => { + if (err) throw new Error("Can't write file to disk"); + }); + } else { + throw new Error('Account import: Cannot recognize keyfile (invalid)'); + } + } catch (err) { + e.sender.send('uiAction_checkedWalletFile', null, 'invalid'); + if ( + /Unexpected token . in JSON at position 0/.test(err.message) === true + ) { + log.error('Account import: Cannot recognize keyfile (no JSON)'); + } else { + log.error(err); + } + } + }); +}); + +// import presale wallet +ipc.on('backendAction_importWalletFile', (e, path, pw) => { + const spawn = require('child_process').spawn; // eslint-disable-line global-require + const ClientBinaryManager = require('./clientBinaryManager'); // eslint-disable-line global-require + let error = false; + + const binPath = ClientBinaryManager.getClient('geth').binPath; + const nodeProcess = spawn(binPath, ['wallet', 'import', path]); + + nodeProcess.once('error', () => { + error = true; + e.sender.send( + 'uiAction_importedWalletFile', + 'Couldn\'t start the "geth wallet import " process.' + ); + }); + nodeProcess.stdout.on('data', _data => { + const data = _data.toString(); + if (data) { + log.info('Imported presale: ', data); + } + + if ( + /Decryption failed|not equal to expected addr|could not decrypt/.test( + data + ) + ) { + e.sender.send('uiAction_importedWalletFile', 'Decryption Failed'); + + // if imported, return the address + } else if (data.indexOf('Address:') !== -1) { + const find = data.match(/\{([a-f0-9]+)\}/i); + if (find.length && find[1]) { + e.sender.send('uiAction_importedWalletFile', null, `0x${find[1]}`); + } else { + e.sender.send('uiAction_importedWalletFile', data); + } + + // if not stop, so we don't kill the process + } else { + return; + } + + nodeProcess.stdout.removeAllListeners('data'); + nodeProcess.removeAllListeners('error'); + nodeProcess.kill('SIGINT'); + }); + + // file password + setTimeout(() => { + if (!error) { + nodeProcess.stdin.write(`${pw}\n`); + pw = null; // eslint-disable-line no-param-reassign + } + }, 2000); +}); + +const createAccountPopup = e => { + Windows.createPopup('requestAccount', { ownerId: e.sender.id }); +}; + +// MIST API +ipc.on('mistAPI_createAccount', createAccountPopup); + +ipc.on('mistAPI_requestAccount', e => { + if (global.mode === 'wallet') { + createAccountPopup(e); + } else { + // Mist + // if coming from wallet, skip connect, go straight to create + if (e.sender.history[0] === 'https://wallet.ethereum.org/') { + createAccountPopup(e); + } else { + Windows.createPopup('connectAccount', { ownerId: e.sender.id }); + } + } +}); + +const uiLoggers = {}; + +ipc.on('console_log', (event, id, logLevel, logItemsStr) => { + try { + const loggerId = `(ui: ${id})`; + + let windowLogger = uiLoggers[loggerId]; + + if (!windowLogger) { + windowLogger = uiLoggers[loggerId] = logger.create(loggerId); + } + + windowLogger[logLevel](..._.toArray(JSON.parse(logItemsStr))); + } catch (err) { + log.error(err); + } +}); + +ipc.on('backendAction_reloadSelectedTab', event => { + event.sender.send('uiAction_reloadSelectedTab'); +}); diff --git a/modules/menuItems.js b/modules/menuItems.js new file mode 100644 index 0000000..95e4fe3 --- /dev/null +++ b/modules/menuItems.js @@ -0,0 +1,698 @@ +const { + app, + BrowserWindow, + ipcMain: ipc, + Menu, + shell, + dialog +} = require('electron'); +const fs = require('fs'); +const path = require('path'); +const Windows = require('./windows'); +const Settings = require('./settings'); +const log = require('./utils/logger').create('menuItems'); +const swarmLog = require('./utils/logger').create('swarm'); +const updateChecker = require('./updateChecker'); +const ethereumNode = require('./ethereumNode.js'); +const ClientBinaryManager = require('./clientBinaryManager'); + +import { + setLanguage, + toggleSwarm, + toggleSwarmOnStart +} from './core/settings/actions'; +import { SwarmState } from './core/settings/reducer'; +import swarmNode from './swarmNode.js'; + +// Make easier to return values for specific systems +const switchForSystem = function(options) { + if (process.platform in options) { + return options[process.platform]; + } else if ('default' in options) { + return options.default; + } + return null; +}; + +// create menu +// null -> null +const createMenu = function(webviews) { + webviews = webviews || []; + + const menu = Menu.buildFromTemplate(menuTempl(webviews)); + Menu.setApplicationMenu(menu); +}; + +const restartNode = function(newType, newNetwork, syncMode, webviews) { + newNetwork = newNetwork || ethereumNode.network; + + log.info('Switch node', newType, newNetwork); + + return ethereumNode + .restart(newType, newNetwork, syncMode) + .then(() => { + Windows.getByType('main').load(global.interfaceAppUrl); + + createMenu(webviews); + log.info('Node switch successful.'); + }) + .catch(err => { + log.error('Error switching node', err); + }); +}; + +const startMining = webviews => { + ethereumNode + .send('miner_start', [1]) + .then(ret => { + log.info('miner_start', ret.result); + + if (ret.result) { + global.mining = true; + createMenu(webviews); + } + }) + .catch(err => { + log.error('miner_start', err); + }); +}; + +const stopMining = webviews => { + ethereumNode + .send('miner_stop', [1]) + .then(ret => { + log.info('miner_stop', ret.result); + + if (ret.result) { + global.mining = false; + createMenu(webviews); + } + }) + .catch(err => { + log.error('miner_stop', err); + }); +}; + +// create a menu template +// null -> obj +let menuTempl = function(webviews) { + const menu = []; + webviews = webviews || []; + + // APP + const fileMenu = []; + + if (process.platform === 'darwin') { + fileMenu.push( + { + label: i18n.t('mist.applicationMenu.app.about', { + app: Settings.appName + }), + click() { + Windows.createPopup('about'); + } + }, + { + label: i18n.t('mist.applicationMenu.app.checkForUpdates'), + click() { + updateChecker.runVisibly(); + } + }, + { + label: i18n.t('mist.applicationMenu.app.checkForNodeUpdates'), + click() { + // remove skipVersion + fs.writeFileSync( + path.join(Settings.userDataPath, 'skippedNodeVersion.json'), + '' // write no version + ); + + // true = will restart after updating and user consent + ClientBinaryManager.init(true); + } + }, + { + type: 'separator' + }, + { + label: i18n.t('mist.applicationMenu.app.services', { + app: Settings.appName + }), + role: 'services', + submenu: [] + }, + { + type: 'separator' + }, + { + label: i18n.t('mist.applicationMenu.app.hide', { + app: Settings.appName + }), + accelerator: 'Command+H', + role: 'hide' + }, + { + label: i18n.t('mist.applicationMenu.app.hideOthers', { + app: Settings.appName + }), + accelerator: 'Command+Alt+H', + role: 'hideothers' + }, + { + label: i18n.t('mist.applicationMenu.app.showAll', { + app: Settings.appName + }), + role: 'unhide' + }, + { + type: 'separator' + } + ); + } + + fileMenu.push({ + label: i18n.t('mist.applicationMenu.app.quit', { + app: Settings.appName + }), + accelerator: 'CommandOrControl+Q', + click() { + app.quit(); + } + }); + + menu.push({ + label: i18n.t('mist.applicationMenu.app.label', { + app: Settings.appName + }), + submenu: fileMenu + }); + + let swarmUpload = []; + if (global.mode !== 'wallet') { + swarmUpload.push( + { + type: 'separator' + }, + { + label: i18n.t('mist.applicationMenu.file.swarmUpload'), + accelerator: 'Shift+CommandOrControl+U', + enabled: store.getState().settings.swarmState == SwarmState.Enabled, + click() { + const focusedWindow = BrowserWindow.getFocusedWindow(); + const paths = dialog.showOpenDialog(focusedWindow, { + properties: ['openFile', 'openDirectory'] + }); + if (paths && paths.length === 1) { + const isDir = fs.lstatSync(paths[0]).isDirectory(); + const defaultPath = path.join(paths[0], 'index.html'); + const uploadConfig = { + path: paths[0], + kind: isDir ? 'directory' : 'file', + defaultFile: fs.existsSync(defaultPath) ? '/index.html' : null + }; + swarmNode + .upload(uploadConfig) + .then(hash => { + focusedWindow.webContents.executeJavaScript(` + Tabs.update('browser', {$set: { + url: 'bzz://${hash}', + redirect: 'bzz://${hash}' + }}); + LocalStore.set('selectedTab', 'browser'); + `); + swarmLog.info('Hash uploaded:', hash); + }) + .catch(e => swarmLog.error(e)); + } + } + } + ); + } + + menu.push({ + label: i18n.t('mist.applicationMenu.file.label'), + submenu: [ + { + label: i18n.t('mist.applicationMenu.file.newAccount'), + accelerator: 'CommandOrControl+N', + click() { + Windows.createPopup('requestAccount'); + } + }, + { + label: i18n.t('mist.applicationMenu.file.importPresale'), + accelerator: 'CommandOrControl+I', + enabled: ethereumNode.isMainNetwork, + click() { + Windows.createPopup('importAccount'); + } + }, + { + type: 'separator' + }, + { + label: i18n.t('mist.applicationMenu.file.backup'), + submenu: [ + { + label: i18n.t('mist.applicationMenu.file.backupKeyStore'), + click() { + let userPath = Settings.userHomePath; + + // eth + if (ethereumNode.isEth) { + if (process.platform === 'win32') { + userPath = `${Settings.appDataPath}\\Web3\\keys`; + } else { + userPath += '/.web3/keys'; + } + + // geth + } else { + if (process.platform === 'darwin') { + userPath += '/Library/EtherCore/keystore'; + } + + if ( + process.platform === 'freebsd' || + process.platform === 'linux' || + process.platform === 'sunos' + ) { + userPath += '/.ethercore/keystore'; + } + + if (process.platform === 'win32') { + userPath = `${Settings.appDataPath}\\EtherCore\\keystore`; + } + } + + shell.showItemInFolder(userPath); + } + }, + { + label: i18n.t('mist.applicationMenu.file.backupMist'), + click() { + shell.openItem(Settings.userDataPath); + } + } + ] + }, + ...swarmUpload + ] + }); + + // EDIT + menu.push({ + label: i18n.t('mist.applicationMenu.edit.label'), + submenu: [ + { + label: i18n.t('mist.applicationMenu.edit.undo'), + accelerator: 'CommandOrControl+Z', + role: 'undo' + }, + { + label: i18n.t('mist.applicationMenu.edit.redo'), + accelerator: 'Shift+CommandOrControl+Z', + role: 'redo' + }, + { + type: 'separator' + }, + { + label: i18n.t('mist.applicationMenu.edit.cut'), + accelerator: 'CommandOrControl+X', + role: 'cut' + }, + { + label: i18n.t('mist.applicationMenu.edit.copy'), + accelerator: 'CommandOrControl+C', + role: 'copy' + }, + { + label: i18n.t('mist.applicationMenu.edit.paste'), + accelerator: 'CommandOrControl+V', + role: 'paste' + }, + { + label: i18n.t('mist.applicationMenu.edit.selectAll'), + accelerator: 'CommandOrControl+A', + role: 'selectall' + } + ] + }); + + // LANGUAGE (VIEW) + const switchLang = langCode => (menuItem, browserWindow) => { + store.dispatch(setLanguage(langCode, browserWindow)); + }; + + const currentLanguage = Settings.language; + const languageMenu = Object.keys(i18n.options.resources) + .filter(langCode => langCode !== 'dev') + .map(langCode => { + const menuItem = { + label: i18n.t(`mist.applicationMenu.view.langCodes.${langCode}`), + type: 'checkbox', + checked: langCode === currentLanguage, + click: switchLang(langCode) + }; + return menuItem; + }); + + languageMenu.unshift( + { + label: i18n.t('mist.applicationMenu.view.default'), + click: switchLang(i18n.getBestMatchedLangCode(app.getLocale())) + }, + { + type: 'separator' + } + ); + + // VIEW + menu.push({ + label: i18n.t('mist.applicationMenu.view.label'), + submenu: [ + { + label: i18n.t('mist.applicationMenu.view.fullscreen'), + accelerator: switchForSystem({ + darwin: 'Command+Control+F', + default: 'F11' + }), + click() { + const mainWindow = Windows.getByType('main'); + + mainWindow.window.setFullScreen(!mainWindow.window.isFullScreen()); + } + }, + { + label: i18n.t('mist.applicationMenu.view.languages'), + submenu: languageMenu + } + ] + }); + + // DEVELOP + const devToolsMenu = []; + let devtToolsSubMenu; + let curWindow; + + // change for wallet + if (Settings.uiMode === 'mist') { + devtToolsSubMenu = [ + { + label: i18n.t('mist.applicationMenu.develop.devToolsMistUI'), + accelerator: 'Alt+CommandOrControl+I', + click() { + curWindow = BrowserWindow.getFocusedWindow(); + if (curWindow) { + curWindow.toggleDevTools(); + } + } + }, + { + type: 'separator' + } + ]; + + // add webviews + webviews.forEach(webview => { + devtToolsSubMenu.push({ + label: i18n.t('mist.applicationMenu.develop.devToolsWebview', { + webview: webview.name + }), + click() { + Windows.getByType('main').send( + 'uiAction_toggleWebviewDevTool', + webview._id + ); + } + }); + }); + + // wallet + } else { + devtToolsSubMenu = [ + { + label: i18n.t('mist.applicationMenu.develop.devToolsWalletUI'), + accelerator: 'Alt+CommandOrControl+I', + click() { + curWindow = BrowserWindow.getFocusedWindow(); + if (curWindow) { + curWindow.toggleDevTools(); + } + } + } + ]; + } + + devToolsMenu.push({ + label: i18n.t('mist.applicationMenu.develop.devTools'), + submenu: devtToolsSubMenu + }); + + if (Settings.uiMode === 'mist') { + devToolsMenu.push({ + label: i18n.t('mist.applicationMenu.develop.openRemix'), + enabled: true, + click() { + Windows.createPopup('remix'); + } + }); + } + + devToolsMenu.push({ + label: i18n.t('mist.applicationMenu.develop.runTests'), + enabled: Settings.uiMode === 'mist', + click() { + Windows.getByType('main').send('uiAction_runTests', 'webview'); + } + }); + + devToolsMenu.push({ + label: i18n.t('mist.applicationMenu.develop.logFiles'), + click() { + try { + shell.showItemInFolder( + path.join(Settings.userDataPath, 'logs', 'all.log') + ); + } catch (error) { + log.error(error); + } + } + }); + + // add node switching menu + devToolsMenu.push({ + type: 'separator' + }); + + // add node switch + if (process.platform === 'darwin' || process.platform === 'win32') { + const nodeSubmenu = []; + + const ethClient = ClientBinaryManager.getClient('eth'); + const gethClient = ClientBinaryManager.getClient('geth'); + + if (gethClient) { + nodeSubmenu.push({ + label: `Geth ${gethClient.version}`, + checked: ethereumNode.isOwnNode && ethereumNode.isGeth, + enabled: ethereumNode.isOwnNode, + type: 'checkbox', + click() { + restartNode('geth', null, 'fast', webviews); + } + }); + } + + if (ethClient) { + nodeSubmenu.push({ + label: `Eth ${ethClient.version} (C++)`, + checked: ethereumNode.isOwnNode && ethereumNode.isEth, + enabled: ethereumNode.isOwnNode, + // enabled: false, + type: 'checkbox', + click() { + restartNode('eth'); + } + }); + } + + devToolsMenu.push({ + label: i18n.t('mist.applicationMenu.develop.ethereumNode'), + submenu: nodeSubmenu + }); + } + + // add network switch + devToolsMenu.push({ + label: i18n.t('mist.applicationMenu.develop.network'), + submenu: [ + { + label: i18n.t('mist.applicationMenu.develop.mainNetwork'), + accelerator: 'CommandOrControl+Alt+1', + checked: ethereumNode.isOwnNode && ethereumNode.isMainNetwork, + enabled: ethereumNode.isOwnNode, + type: 'checkbox', + click() { + restartNode(ethereumNode.type, 'main'); + } + }, + { + label: 'ERE - Test network', + accelerator: 'CommandOrControl+Alt+2', + checked: ethereumNode.isOwnNode && ethereumNode.network === 'test', + enabled: ethereumNode.isOwnNode, + type: 'checkbox', + click() { + restartNode(ethereumNode.type, 'test'); + } + } + ] + }); + + // Light mode switch should appear when not in Solo Mode (dev network) + // if ( + // ethereumNode.isOwnNode && + // ethereumNode.isGeth && + // !ethereumNode.isDevNetwork + // ) { + // devToolsMenu.push({ + // label: 'Sync with Light client (beta)', + // enabled: true, + // checked: ethereumNode.isLightMode, + // type: 'checkbox', + // click() { + // restartNode('geth', null, ethereumNode.isLightMode ? 'fast' : 'light'); + // } + // }); + // } + + // Enables mining menu: only in Solo mode and Ropsten network (testnet) + if ( + ethereumNode.isOwnNode && + (ethereumNode.isTestNetwork || ethereumNode.isDevNetwork) + ) { + devToolsMenu.push({ + label: global.mining + ? i18n.t('mist.applicationMenu.develop.stopMining') + : i18n.t('mist.applicationMenu.develop.startMining'), + accelerator: 'CommandOrControl+Shift+M', + enabled: true, + click() { + if (global.mining) { + stopMining(webviews); + } else { + startMining(webviews); + } + } + }); + } + + if (global.mode !== 'wallet') { + devToolsMenu.push( + { + type: 'separator' + }, + { + label: i18n.t('mist.applicationMenu.develop.enableSwarm'), + enabled: true, + checked: [SwarmState.Enabling, SwarmState.Enabled].includes( + global.store.getState().settings.swarmState + ), + type: 'checkbox', + click() { + store.dispatch(toggleSwarm()); + } + } + ); + } + + menu.push({ + label: + (global.mining ? '⛏ ' : '') + + i18n.t('mist.applicationMenu.develop.label'), + submenu: devToolsMenu + }); + + // WINDOW + menu.push({ + label: i18n.t('mist.applicationMenu.window.label'), + role: 'window', + submenu: [ + { + label: i18n.t('mist.applicationMenu.window.minimize'), + accelerator: 'CommandOrControl+M', + role: 'minimize' + }, + { + label: i18n.t('mist.applicationMenu.window.close'), + accelerator: 'CommandOrControl+W', + role: 'close' + }, + { + type: 'separator' + }, + { + label: i18n.t('mist.applicationMenu.window.toFront'), + role: 'front' + } + ] + }); + + // HELP + const helpMenu = []; + + if ( + process.platform === 'freebsd' || + process.platform === 'linux' || + process.platform === 'sunos' || + process.platform === 'win32' + ) { + helpMenu.push( + { + label: i18n.t('mist.applicationMenu.app.about', { + app: Settings.appName + }), + click() { + Windows.createPopup('about'); + } + }, + { + label: i18n.t('mist.applicationMenu.app.checkForUpdates'), + click() { + updateChecker.runVisibly(); + } + } + ); + } + helpMenu.push( + { + label: i18n.t('mist.applicationMenu.help.discord'), + click() { + shell.openExternal('https://discord.gg/3XQRbNk'); + } + }, + { + label: i18n.t('mist.applicationMenu.help.reddit'), + click() { + shell.openExternal('https://www.reddit.com/u/ethercore'); + } + }, + { + label: i18n.t('mist.applicationMenu.help.reportBug'), + click() { + shell.openExternal('https://github.com/ethercore/desktop-wallet/issues'); + } + } + ); + + menu.push({ + label: i18n.t('mist.applicationMenu.help.label'), + role: 'help', + submenu: helpMenu + }); + return menu; +}; + +module.exports = createMenu; diff --git a/modules/nodeSync.js b/modules/nodeSync.js new file mode 100644 index 0000000..e3b358f --- /dev/null +++ b/modules/nodeSync.js @@ -0,0 +1,200 @@ +/** +The nodeSync module, +checks the current node whether its synching or not and how much it kept up already. + +@module nodeSync +*/ + +const _ = global._; +const Q = require('bluebird'); +const EventEmitter = require('events').EventEmitter; +const { ipcMain: ipc } = require('electron'); +const ethereumNode = require('./ethereumNode'); +const log = require('./utils/logger').create('NodeSync'); + +const SYNC_CHECK_INTERVAL_MS = 2000; + +class NodeSync extends EventEmitter { + constructor() { + super(); + + ethereumNode.on('state', _.bind(this._onNodeStateChanged, this)); + } + + /** + * @return {Promise} + */ + start() { + if (this._syncPromise) { + log.warn('Sync already in progress, returning Promise'); + + return Q.resolve(this._syncPromise); + } + + this._syncPromise = Q.try(() => { + if (!ethereumNode.isIpcConnected) { + throw new Error('Cannot sync - EtherCore node not yet connected'); + } + + return new Q((resolve, reject) => { + log.info('Starting sync loop'); + + this._syncInProgress = true; + this._onSyncDone = resolve; + this._onSyncError = reject; + + this.emit('starting'); + + ipc.on('backendAction_skipSync', () => { + ipc.removeAllListeners('backendAction_skipSync'); + log.info('Sync has been skipped'); + + this._onSyncDone(); + }); + + this._sync(); + }); + }) + .then(() => { + this.emit('finished'); + }) + .catch(err => { + log.error('Sync error', err); + + this.emit('error', err); + }) + .finally(() => { + log.info('Sync loop ended'); + + this._clearState(); + }); + + return this._syncPromise; + } + + /** + * @return {Promise} + */ + stop() { + return Q.try(() => { + if (!this._syncInProgress) { + log.debug('Sync not already in progress.'); + } else { + log.info('Stopping sync loop'); + + this._clearState(); + + return Q.delay(SYNC_CHECK_INTERVAL_MS).then(() => { + this.emit('stopped'); + }); + } + }); + } + + _clearState() { + ipc.removeAllListeners('backendAction_skipSync'); + + this._syncInProgress = this._syncPromise = this._onSyncDone = this._onSyncError = false; + } + + _sync() { + _.delay(() => { + if (!this._syncInProgress) { + log.debug('Sync no longer in progress, so ending sync loop.'); + + return; + } + + log.trace('Check sync status'); + + ethereumNode + .send('eth_syncing', []) + .then(ret => { + const result = ret.result; + + // got a result, check for error + if (result) { + log.trace('Sync status', result); + + // got an error? + if (result.error) { + if (result.error.code === -32601) { + log.warn('Sync method not implemented, skipping sync.'); + + return this._onSyncDone(); + } + + throw new Error(`Unexpected error: ${result.error}`); + } else { + // no error, so call again in a bit + this.emit('nodeSyncing', result); + + return this._sync(); + } + } else { + // got no result, let's check the block number + log.debug('Check latest block number'); + + return ethereumNode + .send('eth_getBlockByNumber', ['latest', false]) + .then(ret2 => { + const blockResult = ret2.result; + const now = Math.floor(new Date().getTime() / 1000); + + if (!blockResult) { + return this._sync(); + } + + log.debug( + `Last block: ${Number(blockResult.number)}; timestamp: ${ + blockResult.timestamp + }` + ); + + const diff = now - +blockResult.timestamp; + + // need sync if > 1 minute + if (diff > 60) { + this.emit('nodeSyncing', result); + + log.trace('Keep syncing...'); + + return this._sync(); + } + + log.info('No more sync necessary'); + + return this._onSyncDone(); + }); + } + }) + .catch(err => { + log.error('Node crashed while syncing?', err); + + this._onSyncError(err); + }); + }, SYNC_CHECK_INTERVAL_MS); + } + + _onNodeStateChanged(state) { + switch (state) { // eslint-disable-line default-case + // stop syncing when node about to be stopped + case ethereumNode.STATES.STOPPING: + log.info('EtherCore node stopping, so stop sync'); + + this.stop(); + break; + // auto-sync whenever node gets connected + case ethereumNode.STATES.CONNECTED: + log.info('EtherCore node connected, re-start sync'); + + // stop syncing, then start again + this.stop().then(() => { + this.start(); + }); + break; + } + } +} + +module.exports = new NodeSync(); diff --git a/modules/preloader/.eslintrc.yml b/modules/preloader/.eslintrc.yml new file mode 100644 index 0000000..35f46c4 --- /dev/null +++ b/modules/preloader/.eslintrc.yml @@ -0,0 +1,2 @@ +globals: + Helpers: true diff --git a/modules/preloader/browser.js b/modules/preloader/browser.js new file mode 100644 index 0000000..f469657 --- /dev/null +++ b/modules/preloader/browser.js @@ -0,0 +1,166 @@ +/** +@module preloader browser +*/ +const _ = require('underscore'); +require('./include/common')('browser'); +const { ipcRenderer, webFrame, remote } = require('electron'); +const mist = require('./include/mistAPI.js'); +require('./include/getFavicon.js'); +require('./include/getMetaTags.js'); +require('./include/setBasePath')('interface'); +const packageJson = require('./../../package.json'); +const fs = remote.require('fs'); +const path = remote.require('path'); + +// set navigator.language +Object.defineProperty(navigator, 'language', { + get() { + return ipcRenderer.sendSync('backendAction_getLanguage'); + } +}); + +// notifiy the tab to store the webview id +ipcRenderer.sendToHost('setWebviewId'); + +const isValidJsonRpc = function(message) { + return !!( + Object.prototype.hasOwnProperty.call(message, 'method') || + Object.prototype.hasOwnProperty.call(message, 'id') || + Object.prototype.hasOwnProperty.call(message, 'params') || + Object.prototype.hasOwnProperty.call(message, 'jsonrpc') + ); +}; + +const sanatizeJsonRpc = function(message) { + // sanitize + return { + jsonrpc: message.jsonrpc, + id: message.id, + method: message.method, + params: message.params + }; +}; + +// Wait for post messages +window.addEventListener('message', function message(event) { + let data; + try { + data = JSON.parse(event.data); + } catch (e) { + data = event.data; + } + + if (typeof data !== 'object') { + return; + } + + // EthereumProvider: connect + if (data.type === 'create') { + ipcRenderer.send('ipcProvider-create'); + + // EthereumProvider: write + } else if (data.type === 'write') { + let messageIsArray = _.isArray(data.message); + + // only accept valid JSON rpc requests + if (messageIsArray) { + for (let i = 0; i < data.message.length; i++) { + if (isValidJsonRpc(data.message[i])) { + data.message[i] = sanatizeJsonRpc(data.message[i]); + } else { + return; + } + } + } else { + if (isValidJsonRpc(data.message)) { + data.message = sanatizeJsonRpc(data.message); + } else { + return; + } + } + + // make sure we only send allowed properties + ipcRenderer.send('ipcProvider-write', JSON.stringify(data.message)); + + // mistAPI + } else if (/^mistAPI_[a-z]/i.test(data.type)) { + if (data.type === 'mistAPI_requestAccount') { + ipcRenderer.send(data.type, data.message); + } else { + ipcRenderer.sendToHost(data.type, data.message); + } + } +}); + +const postMessage = function(payload) { + if (typeof payload === 'object') { + payload = JSON.stringify(payload); + } + + window.postMessage( + payload, + !location.origin || location.origin === 'null' ? '*' : location.origin + ); +}; + +// custom Events +['uiAction_windowMessage', 'mistAPI_callMenuFunction'].forEach(function(type) { + ipcRenderer.on(type, function onIpcRenderer(e, result) { + // this type needs special packaging + if (type === 'uiAction_windowMessage') { + result = { + type: arguments[1], + error: arguments[2], + value: arguments[3] + }; + } + + postMessage({ + type: type, + message: result + }); + }); +}); + +// add IPCbackend events +['data', 'error', 'end', 'timeout', 'connect'].forEach(function(type) { + ipcRenderer.on(`ipcProvider-` + type, function onIpcRenderer(e, result) { + postMessage({ + type: type, + message: JSON.parse(result) + }); + }); +}); + +// load ethereumProvider +const bignumber = fs + .readFileSync(path.join(__dirname, '/injected/BigNumber.js')) + .toString(); +const eventEmitter3 = fs + .readFileSync(path.join(__dirname, '/injected/EventEmitter3.js')) + .toString(); +let mistAPI = fs + .readFileSync(path.join(__dirname, '/injected/mistAPI.js')) + .toString(); +const ethereumProvider = fs + .readFileSync(path.join(__dirname, '/injected/EthereumProvider.js')) + .toString(); + +mistAPI = mistAPI + .replace('__version__', packageJson.version) + .replace('__license__', packageJson.license) + .replace('__platform__', process.platform) + .replace( + '__solidityVersion__', + String(packageJson.dependencies.solc).match(/\d+\.\d+\.\d+/)[0] + ); + +webFrame.executeJavaScript( + mistAPI + bignumber + eventEmitter3 + ethereumProvider +); + +// notifiy the tab to store the webview id +ipcRenderer.sendToHost('setWebviewId'); + +// destroy the old socket +ipcRenderer.send('ipcProvider-destroy'); diff --git a/modules/preloader/dapps.js b/modules/preloader/dapps.js new file mode 100644 index 0000000..38cbd38 --- /dev/null +++ b/modules/preloader/dapps.js @@ -0,0 +1,4 @@ +/** +@module preloader dapps +*/ +require('./browser.js'); diff --git a/modules/preloader/include/common.js b/modules/preloader/include/common.js new file mode 100644 index 0000000..a53e7b1 --- /dev/null +++ b/modules/preloader/include/common.js @@ -0,0 +1,16 @@ +module.exports = windowType => { + const { ipcRenderer, webFrame } = require('electron'); + + if (process.env.TEST_MODE) { + window.electronRequire = require; + } + + // disable pinch zoom + webFrame.setZoomLevelLimits(1, 1); + + require('./consoleLogCapture')(windowType); // !!! + require('./suppressWindowPrompt')(); + + // register with window manager + ipcRenderer.send('backendAction_setWindowId'); +}; diff --git a/modules/preloader/include/consoleLogCapture.js b/modules/preloader/include/consoleLogCapture.js new file mode 100644 index 0000000..1875693 --- /dev/null +++ b/modules/preloader/include/consoleLogCapture.js @@ -0,0 +1,60 @@ +const { ipcRenderer } = require('electron'); + +const extractLineNumberFromStack = function(stack) { + // / + // / Get the line/filename detail from a Webkit stack trace. See http://stackoverflow.com/a/3806596/1037948 + // / + // / the stack string + + let line = stack.split('\n')[2]; + // fix for various display text + if (line) { + line = + line.indexOf(' (') >= 0 + ? line.split(' (')[1].substring(0, line.length - 1) + : line.split('at ')[1]; + return line; + } +}; + +module.exports = function(windowId) { + if (typeof window === 'undefined') { + return; + } + + windowId = windowId || window.location.url; + + const console = window.console; + + // send console logging to IPC backend + ['trace', 'debug', 'info', 'warn', 'error', 'log'].forEach(method => { + console[`_${method}`] = console[method]; + console[method] = (function(origMethod) { + return function() { + const args = Array.from(arguments); + + const suffix = `@ ${ + this.lineNumber + ? `${this.fileName}:${this.lineNumber}:1` + : extractLineNumberFromStack(new Error().stack) + }`; + + origMethod.apply(console, args.concat([suffix])); + + try { + ipcRenderer.send( + 'console_log', + windowId, + method === 'log' ? 'info' : method, + JSON.stringify(args) + ); + } catch (err) { + console._warn( + 'Unable to stringify arguments to log to backend', + err.stack + ); + } + }; + })(console[method]); + }); +}; diff --git a/modules/preloader/include/getFavicon.js b/modules/preloader/include/getFavicon.js new file mode 100644 index 0000000..af30520 --- /dev/null +++ b/modules/preloader/include/getFavicon.js @@ -0,0 +1,28 @@ +/** +Gets the favicon url + +@module getFavicon +*/ + +const { ipcRenderer } = require('electron'); + +(function() { + document.addEventListener('DOMContentLoaded', DOMContentLoaded, false); + + function DOMContentLoaded(event) { + const icon = + document.querySelector('link[rel="apple-touch-icon"]') || + document.querySelector('link[type="image/x-icon"]') || + document.querySelector('link[rel="shortcut"]') || + document.querySelector('link[rel="shortcut icon"]') || + document.querySelector('link[rel="icon"]'); + + if (icon) { + ipcRenderer.sendToHost('favicon', icon.href); + } else { + ipcRenderer.sendToHost('favicon', null); + } + + document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false); + } +})(); diff --git a/modules/preloader/include/getMetaTags.js b/modules/preloader/include/getMetaTags.js new file mode 100644 index 0000000..815cd9d --- /dev/null +++ b/modules/preloader/include/getMetaTags.js @@ -0,0 +1,25 @@ +/** +Gest the meta[name="ethereum-dapp-url-bar-style"] meta tag + +@module getMetaTags +*/ + +const { ipcRenderer } = require('electron'); + +module.export = (function() { + document.addEventListener('DOMContentLoaded', DOMContentLoaded, false); + + function DOMContentLoaded(event) { + const appBar = document.querySelector( + 'meta[name="ethereum-dapp-url-bar-style"]' + ); + + if (appBar) { + ipcRenderer.sendToHost('appBar', appBar.content); + } else { + ipcRenderer.sendToHost('appBar', null); + } + + document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false); + } +})(); diff --git a/modules/preloader/include/legacyWeb3IpcProvider.js b/modules/preloader/include/legacyWeb3IpcProvider.js new file mode 100644 index 0000000..2f3b19d --- /dev/null +++ b/modules/preloader/include/legacyWeb3IpcProvider.js @@ -0,0 +1,207 @@ +/* + This file is part of web3.js. + + web3.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + web3.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with web3.js. If not, see . +*/ +/** @file ipcprovider.js + * @authors: + * Fabian Vogelsteller + * @date 2015 + */ + +'use strict'; + +var _ = require('underscore'); +var errors = { + InvalidConnection: function(host) { + return new Error( + "CONNECTION ERROR: Couldn't connect to node " + host + '.' + ); + }, + InvalidResponse: function(result) { + var message = + !!result && !!result.error && !!result.error.message + ? result.error.message + : 'Invalid JSON RPC response: ' + JSON.stringify(result); + return new Error(message); + } +}; + +var IpcProvider = function(path, net) { + var _this = this; + this.responseCallbacks = {}; + this.path = path; + + this.connection = net.connect({ path: this.path }); + + this.connection.on('error', function(e) { + console.error('IPC Connection Error', e); + _this._timeout(); + }); + + this.connection.on('end', function() { + _this._timeout(); + }); + + // LISTEN FOR CONNECTION RESPONSES + this.connection.on('data', function(data) { + /*jshint maxcomplexity: 6 */ + + _this._parseResponse(data.toString()).forEach(function(result) { + var id = null; + + // get the id which matches the returned id + if (_.isArray(result)) { + result.forEach(function(load) { + if (_this.responseCallbacks[load.id]) id = load.id; + }); + } else { + id = result.id; + } + + // fire the callback + if (_this.responseCallbacks[id]) { + _this.responseCallbacks[id](null, result); + delete _this.responseCallbacks[id]; + } + }); + }); +}; + +/** +Will parse the response and make an array out of it. + +@method _parseResponse +@param {String} data +*/ +IpcProvider.prototype._parseResponse = function(data) { + var _this = this, + returnValues = []; + + // DE-CHUNKER + var dechunkedData = data + .replace(/\}[\n\r]?\{/g, '}|--|{') // }{ + .replace(/\}\][\n\r]?\[\{/g, '}]|--|[{') // }][{ + .replace(/\}[\n\r]?\[\{/g, '}|--|[{') // }[{ + .replace(/\}\][\n\r]?\{/g, '}]|--|{') // }]{ + .split('|--|'); + + dechunkedData.forEach(function(data) { + // prepend the last chunk + if (_this.lastChunk) data = _this.lastChunk + data; + + var result = null; + + try { + result = JSON.parse(data); + } catch (e) { + _this.lastChunk = data; + + // start timeout to cancel all requests + clearTimeout(_this.lastChunkTimeout); + _this.lastChunkTimeout = setTimeout(function() { + _this._timeout(); + throw errors.InvalidResponse(data); + }, 1000 * 15); + + return; + } + + // cancel timeout and set chunk to null + clearTimeout(_this.lastChunkTimeout); + _this.lastChunk = null; + + if (result) returnValues.push(result); + }); + + return returnValues; +}; + +/** +Get the adds a callback to the responseCallbacks object, +which will be called if a response matching the response Id will arrive. + +@method _addResponseCallback +*/ +IpcProvider.prototype._addResponseCallback = function(payload, callback) { + var id = payload.id || payload[0].id; + var method = payload.method || payload[0].method; + + this.responseCallbacks[id] = callback; + this.responseCallbacks[id].method = method; +}; + +/** +Timeout all requests when the end/error event is fired + +@method _timeout +*/ +IpcProvider.prototype._timeout = function() { + for (var key in this.responseCallbacks) { + if (this.responseCallbacks.hasOwnProperty(key)) { + this.responseCallbacks[key](errors.InvalidConnection('on IPC')); + delete this.responseCallbacks[key]; + } + } +}; + +/** +Check if the current connection is still valid. + +@method isConnected +*/ +IpcProvider.prototype.isConnected = function() { + var _this = this; + + // try reconnect, when connection is gone + if (!_this.connection.writable) + _this.connection.connect({ path: _this.path }); + + return !!this.connection.writable; +}; + +IpcProvider.prototype.send = function(payload) { + if (this.connection.writeSync) { + var result; + + // try reconnect, when connection is gone + if (!this.connection.writable) this.connection.connect({ path: this.path }); + + var data = this.connection.writeSync(JSON.stringify(payload)); + + try { + result = JSON.parse(data); + } catch (e) { + throw errors.InvalidResponse(data); + } + + return result; + } else { + throw new Error( + 'You tried to send "' + + payload.method + + '" synchronously. Synchronous requests are not supported by the IPC provider.' + ); + } +}; + +IpcProvider.prototype.sendAsync = function(payload, callback) { + // try reconnect, when connection is gone + if (!this.connection.writable) this.connection.connect({ path: this.path }); + + this.connection.write(JSON.stringify(payload)); + this._addResponseCallback(payload, callback); +}; + +module.exports = IpcProvider; diff --git a/modules/preloader/include/mistAPI.js b/modules/preloader/include/mistAPI.js new file mode 100644 index 0000000..1b985fd --- /dev/null +++ b/modules/preloader/include/mistAPI.js @@ -0,0 +1,243 @@ +/** +@module MistAPI +*/ + +const _ = require('underscore'); +const { ipcRenderer } = require('electron'); +const packageJson = require('./../../../package.json'); + +module.exports = () => { + let queue = []; + const prefix = 'entry_'; + const MIST_SUBMENU_LIMIT = 100; + + // todo: error handling + const filterAdd = options => { + if (!(options instanceof Object)) { + return false; + } + + return ['name'].every(e => e in options); + }; + + // filterId the id to only contain a-z A-Z 0-9 + const filterId = str => { + const filteredStr = String(str); + let newStr = ''; + if (filteredStr) { + for (let i = 0; i < filteredStr.length; i += 1) { + if (/[a-zA-Z0-9_-]/.test(filteredStr.charAt(i))) { + newStr += filteredStr.charAt(i); + } + } + } + return newStr; + }; + + /** + Mist API + + Provides an API for all dapps, which specifically targets features from the Mist browser + + @class mist + @constructor + */ + const mist = { + callbacks: {}, + version: packageJson.version, + license: packageJson.license, + platform: process.platform, + requestAccount(callback) { + if (callback) { + if (!this.callbacks.connectAccount) { + this.callbacks.connectAccount = []; + } + this.callbacks.connectAccount.push(callback); + } + + ipcRenderer.send('mistAPI_requestAccount'); + }, + solidity: { + version: String(packageJson.dependencies.solc).match(/\d+\.\d+\.\d+/)[0] + }, + sounds: { + bip: function playSound() { + ipcRenderer.sendToHost( + 'mistAPI_sound', + `file://${__dirname}/../../../sounds/bip.mp3` + ); + }, + bloop: function playSound() { + ipcRenderer.sendToHost( + 'mistAPI_sound', + `file://${__dirname}/../../../sounds/bloop.mp3` + ); + }, + invite: function playSound() { + ipcRenderer.sendToHost( + 'mistAPI_sound', + `file://${__dirname}/../../../sounds/invite.mp3` + ); + } + }, + menu: { + entries: {}, + /** + Sets the badge text for the apps menu button + + Example + + mist.menu.setBadge('Some Text') + + @method setBadge + @param {String} text + */ + setBadge(text) { + ipcRenderer.sendToHost('mistAPI_setBadge', text); + }, + /** + Adds/Updates a menu entry + + Example + + mist.menu.add('tkrzU', { + name: 'My Meny Entry', + badge: 50, + position: 1, + selected: true + }, function(){ + // Router.go('/chat/1245'); + }) + + @method add + @param {String} id The id of the menu, has to be the same accross page reloads. + @param {Object} options The menu options like {badge: 23, name: 'My Entry'} + @param {Function} callback Change the callback to be called when the menu is pressed. + */ + add(id, options, callback) { + const args = Array.prototype.slice.call(arguments); + callback = _.isFunction(args[args.length - 1]) ? args.pop() : null; + options = _.isObject(args[args.length - 1]) ? args.pop() : null; + id = + _.isString(args[args.length - 1]) || _.isFinite(args[args.length - 1]) + ? args.pop() + : null; + + if (!filterAdd(options)) { + return false; + } + + const filteredId = prefix + filterId(id); + + // restricting to 100 menu entries + if ( + !(filteredId in this.entries) && + Object.keys(this.entries).length >= MIST_SUBMENU_LIMIT + ) { + return false; + } + + const entry = { + id: filteredId || 'mist_defaultId', + position: options.position, + selected: !!options.selected, + name: options.name, + badge: options.badge + }; + + queue.push({ + action: 'addMenu', + entry + }); + + if (callback) { + entry.callback = callback; + } + + this.entries[filteredId] = entry; + return true; + }, + /** + Updates a menu entry from the mist sidebar. + + @method update + @param {String} id The id of the menu, has to be the same accross page reloads. + @param {Object} options The menu options like {badge: 23, name: 'My Entry'} + @param {Function} callback Change the callback to be called when the menu is pressed. + */ + update() { + this.add.apply(this, arguments); + }, + /** + Removes a menu entry from the mist sidebar. + + @method remove + @param {String} id + @param {String} id The id of the menu, has to be the same accross page reloads. + @param {Object} options The menu options like {badge: 23, name: 'My Entry'} + @param {Function} callback Change the callback to be called when the menu is pressed. + */ + remove(id) { + const filteredId = prefix + filterId(id); + + delete this.entries[filteredId]; + + queue.push({ + action: 'removeMenu', + filteredId + }); + }, + /** + Marks a menu entry as selected + + @method select + @param {String} id + */ + select(id) { + const filteredId = prefix + filterId(id); + queue.push({ action: 'selectMenu', id: filteredId }); + + for (const e in this.entries) { + if ({}.hasOwnProperty.call(this.entries, e)) { + this.entries[e].selected = e === filteredId; + } + } + }, + /** + Removes all menu entries. + + @method clear + */ + clear() { + this.entries = {}; + queue.push({ action: 'clearMenu' }); + } + } + }; + + ipcRenderer.on('mistAPI_callMenuFunction', (e, id) => { + if (mist.menu.entries[id] && mist.menu.entries[id].callback) { + mist.menu.entries[id].callback(); + } + }); + + ipcRenderer.on('uiAction_windowMessage', (e, type, error, value) => { + console.log('uiAction_windowMessage', type, error, value); + if (mist.callbacks[type]) { + mist.callbacks[type].forEach(cb => { + cb(error, value); + }); + delete mist.callbacks[type]; + } + }); + + // work up queue every 500ms + setInterval(() => { + if (queue.length > 0) { + ipcRenderer.sendToHost('mistAPI_menuChanges', queue); + queue = []; + } + }, 500); + + return mist; +}; diff --git a/modules/preloader/include/openExternal.js b/modules/preloader/include/openExternal.js new file mode 100644 index 0000000..d596fc4 --- /dev/null +++ b/modules/preloader/include/openExternal.js @@ -0,0 +1,32 @@ +/** +Opens windows and popups + +@module openExternal +*/ + +const { shell } = require('electron'); + +// open a[target="_blank"] in external browser +document.addEventListener( + 'click', + e => { + let node = false; + + if (e.target.nodeName === 'A') { + node = e.target; + } else if (e.target.parentNode && e.target.parentNode.nodeName === 'A') { + node = e.target.parentNode; + } + + // open in browser + if ( + node && + node.attributes.target && + node.attributes.target.value === '_blank' + ) { + e.preventDefault(); + shell.openExternal(node.href); + } + }, + false +); diff --git a/modules/preloader/include/setBasePath.js b/modules/preloader/include/setBasePath.js new file mode 100644 index 0000000..938b384 --- /dev/null +++ b/modules/preloader/include/setBasePath.js @@ -0,0 +1,19 @@ +/** +Sets the base path in production for the file protocol, so assets are loaded properly + +@module setBasePath +*/ + +const { remote } = require('electron'); +const path = require('path'); + +module.exports = appPath => { + // set the base path for relative assets in production mode + if (remote.getGlobal('production') && ~location.origin.indexOf('file://')) { + window.basePathHref = `${String( + path.resolve(`${__dirname}/../../${appPath}`) + ) + .replace(/\\/g, '/') + .replace('/interface', '/app.asar/interface')}/`; + } +}; diff --git a/modules/preloader/include/suppressWindowPrompt.js b/modules/preloader/include/suppressWindowPrompt.js new file mode 100644 index 0000000..74ca5a5 --- /dev/null +++ b/modules/preloader/include/suppressWindowPrompt.js @@ -0,0 +1,5 @@ +module.exports = () => { + window.prompt = () => { + console.warn("Mist doesn't support window.prompt()"); + }; +}; diff --git a/modules/preloader/include/web3CurrentProvider.js b/modules/preloader/include/web3CurrentProvider.js new file mode 100644 index 0000000..1beb5ad --- /dev/null +++ b/modules/preloader/include/web3CurrentProvider.js @@ -0,0 +1,21 @@ +/** +Sets the ethereum provider, as well as "web3" for backwards compatibility. + +@module ethereumProvider +*/ +const Web3 = require('web3'); +const BigNumber = require('bignumber.js'); +const ipcProviderWrapper = require('../../ipc/ipcProviderWrapper.js'); +const LegacyWeb3IpcProvider = require('./legacyWeb3IpcProvider.js'); + +// SET ETHEREUM PROVIDER +// window.ethereumProvider = new Web3.providers.IpcProvider('', ipcProviderWrapper); + +// LEGACY +window.BigNumber = BigNumber; +window.web3 = { + currentProvider: new LegacyWeb3IpcProvider('', ipcProviderWrapper) +}; + +// for now still add this too: WILL BE REMOVED with web3 1.0 +window.web3 = new Web3(new Web3.providers.IpcProvider('', ipcProviderWrapper)); diff --git a/modules/preloader/injected/BigNumber.js b/modules/preloader/injected/BigNumber.js new file mode 100644 index 0000000..89a4661 --- /dev/null +++ b/modules/preloader/injected/BigNumber.js @@ -0,0 +1,1321 @@ +(function() { + /* bignumber.js v4.0.0 https://github.com/MikeMcl/bignumber.js/LICENCE */ + !(function(e) { + 'use strict'; + function n(e) { + function a(e, n) { + var t, + r, + i, + o, + u, + s, + l = this; + if (!(l instanceof a)) + return z && x(26, 'constructor call without new', e), new a(e, n); + if (null != n && V(n, 2, 64, C, 'base')) { + if (((n = 0 | n), (s = e + ''), 10 == n)) + return (l = new a(e instanceof a ? e : s)), I(l, B + l.e + 1, P); + if ( + ((o = 'number' == typeof e) && 0 * e != 0) || + !new RegExp( + '^-?' + (t = '[' + v.slice(0, n) + ']+') + '(?:\\.' + t + ')?$', + 37 > n ? 'i' : '' + ).test(s) + ) + return U(l, s, o, n); + o + ? ((l.s = 0 > 1 / e ? ((s = s.slice(1)), -1) : 1), + z && s.replace(/^0\.0*|\./, '').length > 15 && x(C, w, e), + (o = !1)) + : (l.s = 45 === s.charCodeAt(0) ? ((s = s.slice(1)), -1) : 1), + (s = A(s, 10, n, l.s)); + } else { + if (e instanceof a) + return ( + (l.s = e.s), + (l.e = e.e), + (l.c = (e = e.c) ? e.slice() : e), + void (C = 0) + ); + if ((o = 'number' == typeof e) && 0 * e == 0) { + if (((l.s = 0 > 1 / e ? ((e = -e), -1) : 1), e === ~~e)) { + for (r = 0, i = e; i >= 10; i /= 10, r++); + return (l.e = r), (l.c = [e]), void (C = 0); + } + s = e + ''; + } else { + if (!h.test((s = e + ''))) return U(l, s, o); + l.s = 45 === s.charCodeAt(0) ? ((s = s.slice(1)), -1) : 1; + } + } + for ( + (r = s.indexOf('.')) > -1 && (s = s.replace('.', '')), + (i = s.search(/e/i)) > 0 + ? (0 > r && (r = i), + (r += +s.slice(i + 1)), + (s = s.substring(0, i))) + : 0 > r && (r = s.length), + i = 0; + 48 === s.charCodeAt(i); + i++ + ); + for (u = s.length; 48 === s.charCodeAt(--u); ); + if ((s = s.slice(i, u + 1))) + if ( + ((u = s.length), + o && z && u > 15 && (e > y || e !== p(e)) && x(C, w, l.s * e), + (r = r - i - 1), + r > G) + ) + l.c = l.e = null; + else if ($ > r) l.c = [(l.e = 0)]; + else { + if ( + ((l.e = r), + (l.c = []), + (i = (r + 1) % b), + 0 > r && (i += b), + u > i) + ) { + for (i && l.c.push(+s.slice(0, i)), u -= b; u > i; ) + l.c.push(+s.slice(i, (i += b))); + (s = s.slice(i)), (i = b - s.length); + } else i -= u; + for (; i--; s += '0'); + l.c.push(+s); + } + else l.c = [(l.e = 0)]; + C = 0; + } + function A(e, n, t, i) { + var o, + u, + l, + c, + h, + g, + p, + d = e.indexOf('.'), + m = B, + w = P; + for ( + 37 > t && (e = e.toLowerCase()), + d >= 0 && + ((l = W), + (W = 0), + (e = e.replace('.', '')), + (p = new a(t)), + (h = p.pow(e.length - d)), + (W = l), + (p.c = s(f(r(h.c), h.e), 10, n)), + (p.e = p.c.length)), + g = s(e, t, n), + u = l = g.length; + 0 == g[--l]; + g.pop() + ); + if (!g[0]) return '0'; + if ( + (0 > d + ? --u + : ((h.c = g), + (h.e = u), + (h.s = i), + (h = L(h, p, m, w, n)), + (g = h.c), + (c = h.r), + (u = h.e)), + (o = u + m + 1), + (d = g[o]), + (l = n / 2), + (c = c || 0 > o || null != g[o + 1]), + (c = + 4 > w + ? (null != d || c) && (0 == w || w == (h.s < 0 ? 3 : 2)) + : d > l || + (d == l && + (4 == w || + c || + (6 == w && 1 & g[o - 1]) || + w == (h.s < 0 ? 8 : 7)))), + 1 > o || !g[0]) + ) + e = c ? f('1', -m) : '0'; + else { + if (((g.length = o), c)) + for (--n; ++g[--o] > n; ) (g[o] = 0), o || (++u, g.unshift(1)); + for (l = g.length; !g[--l]; ); + for (d = 0, e = ''; l >= d; e += v.charAt(g[d++])); + e = f(e, u); + } + return e; + } + function E(e, n, t, i) { + var o, u, s, c, h; + if (((t = null != t && V(t, 0, 8, i, m) ? 0 | t : P), !e.c)) + return e.toString(); + if (((o = e.c[0]), (s = e.e), null == n)) + (h = r(e.c)), + (h = 19 == i || (24 == i && q >= s) ? l(h, s) : f(h, s)); + else if ( + ((e = I(new a(e), n, t)), + (u = e.e), + (h = r(e.c)), + (c = h.length), + 19 == i || (24 == i && (u >= n || q >= u))) + ) { + for (; n > c; h += '0', c++); + h = l(h, u); + } else if (((n -= s), (h = f(h, u)), u + 1 > c)) { + if (--n > 0) for (h += '.'; n--; h += '0'); + } else if (((n += u - c), n > 0)) + for (u + 1 == c && (h += '.'); n--; h += '0'); + return e.s < 0 && o ? '-' + h : h; + } + function D(e, n) { + var t, + r, + i = 0; + for (u(e[0]) && (e = e[0]), t = new a(e[0]); ++i < e.length; ) { + if (((r = new a(e[i])), !r.s)) { + t = r; + break; + } + n.call(t, r) && (t = r); + } + return t; + } + function F(e, n, t, r, i) { + return ( + (n > e || e > t || e != c(e)) && + x( + r, + (i || 'decimal places') + + (n > e || e > t ? ' out of range' : ' not an integer'), + e + ), + !0 + ); + } + function _(e, n, t) { + for (var r = 1, i = n.length; !n[--i]; n.pop()); + for (i = n[0]; i >= 10; i /= 10, r++); + return ( + (t = r + t * b - 1) > G + ? (e.c = e.e = null) + : $ > t ? (e.c = [(e.e = 0)]) : ((e.e = t), (e.c = n)), + e + ); + } + function x(e, n, t) { + var r = new Error( + [ + 'new BigNumber', + 'cmp', + 'config', + 'div', + 'divToInt', + 'eq', + 'gt', + 'gte', + 'lt', + 'lte', + 'minus', + 'mod', + 'plus', + 'precision', + 'random', + 'round', + 'shift', + 'times', + 'toDigits', + 'toExponential', + 'toFixed', + 'toFormat', + 'toFraction', + 'pow', + 'toPrecision', + 'toString', + 'BigNumber' + ][e] + + '() ' + + n + + ': ' + + t + ); + throw ((r.name = 'BigNumber Error'), (C = 0), r); + } + function I(e, n, t, r) { + var i, + o, + u, + s, + l, + f, + c, + a = e.c, + h = O; + if (a) { + e: { + for (i = 1, s = a[0]; s >= 10; s /= 10, i++); + if (((o = n - i), 0 > o)) + (o += b), + (u = n), + (l = a[(f = 0)]), + (c = ((l / h[i - u - 1]) % 10) | 0); + else if (((f = g((o + 1) / b)), f >= a.length)) { + if (!r) break e; + for (; a.length <= f; a.push(0)); + (l = c = 0), (i = 1), (o %= b), (u = o - b + 1); + } else { + for (l = s = a[f], i = 1; s >= 10; s /= 10, i++); + (o %= b), + (u = o - b + i), + (c = 0 > u ? 0 : ((l / h[i - u - 1]) % 10) | 0); + } + if ( + ((r = + r || + 0 > n || + null != a[f + 1] || + (0 > u ? l : l % h[i - u - 1])), + (r = + 4 > t + ? (c || r) && (0 == t || t == (e.s < 0 ? 3 : 2)) + : c > 5 || + (5 == c && + (4 == t || + r || + (6 == t && + ((o > 0 ? (u > 0 ? l / h[i - u] : 0) : a[f - 1]) % + 10) & + 1) || + t == (e.s < 0 ? 8 : 7)))), + 1 > n || !a[0]) + ) + return ( + (a.length = 0), + r + ? ((n -= e.e + 1), + (a[0] = h[(b - n % b) % b]), + (e.e = -n || 0)) + : (a[0] = e.e = 0), + e + ); + if ( + (0 == o + ? ((a.length = f), (s = 1), f--) + : ((a.length = f + 1), + (s = h[b - o]), + (a[f] = u > 0 ? p((l / h[i - u]) % h[u]) * s : 0)), + r) + ) + for (;;) { + if (0 == f) { + for (o = 1, u = a[0]; u >= 10; u /= 10, o++); + for (u = a[0] += s, s = 1; u >= 10; u /= 10, s++); + o != s && (e.e++, a[0] == N && (a[0] = 1)); + break; + } + if (((a[f] += s), a[f] != N)) break; + (a[f--] = 0), (s = 1); + } + for (o = a.length; 0 === a[--o]; a.pop()); + } + e.e > G ? (e.c = e.e = null) : e.e < $ && (e.c = [(e.e = 0)]); + } + return e; + } + var L, + U, + C = 0, + M = a.prototype, + T = new a(1), + B = 20, + P = 4, + q = -7, + k = 21, + $ = -1e7, + G = 1e7, + z = !0, + V = F, + j = !1, + H = 1, + W = 0, + J = { + decimalSeparator: '.', + groupSeparator: ',', + groupSize: 3, + secondaryGroupSize: 0, + fractionGroupSeparator: ' ', + fractionGroupSize: 0 + }; + return ( + (a.another = n), + (a.ROUND_UP = 0), + (a.ROUND_DOWN = 1), + (a.ROUND_CEIL = 2), + (a.ROUND_FLOOR = 3), + (a.ROUND_HALF_UP = 4), + (a.ROUND_HALF_DOWN = 5), + (a.ROUND_HALF_EVEN = 6), + (a.ROUND_HALF_CEIL = 7), + (a.ROUND_HALF_FLOOR = 8), + (a.EUCLID = 9), + (a.config = a.set = function() { + var e, + n, + t = 0, + r = {}, + i = arguments, + s = i[0], + l = + s && 'object' == typeof s + ? function() { + return s.hasOwnProperty(n) ? null != (e = s[n]) : void 0; + } + : function() { + return i.length > t ? null != (e = i[t++]) : void 0; + }; + return ( + l((n = 'DECIMAL_PLACES')) && V(e, 0, S, 2, n) && (B = 0 | e), + (r[n] = B), + l((n = 'ROUNDING_MODE')) && V(e, 0, 8, 2, n) && (P = 0 | e), + (r[n] = P), + l((n = 'EXPONENTIAL_AT')) && + (u(e) + ? V(e[0], -S, 0, 2, n) && + V(e[1], 0, S, 2, n) && + ((q = 0 | e[0]), (k = 0 | e[1])) + : V(e, -S, S, 2, n) && (q = -(k = 0 | (0 > e ? -e : e)))), + (r[n] = [q, k]), + l((n = 'RANGE')) && + (u(e) + ? V(e[0], -S, -1, 2, n) && + V(e[1], 1, S, 2, n) && + (($ = 0 | e[0]), (G = 0 | e[1])) + : V(e, -S, S, 2, n) && + (0 | e + ? ($ = -(G = 0 | (0 > e ? -e : e))) + : z && x(2, n + ' cannot be zero', e))), + (r[n] = [$, G]), + l((n = 'ERRORS')) && + (e === !!e || 1 === e || 0 === e + ? ((C = 0), (V = (z = !!e) ? F : o)) + : z && x(2, n + d, e)), + (r[n] = z), + l((n = 'CRYPTO')) && + (e === !0 || e === !1 || 1 === e || 0 === e + ? e + ? ((e = 'undefined' == typeof crypto), + !e && + crypto && + (crypto.getRandomValues || crypto.randomBytes) + ? (j = !0) + : z + ? x(2, 'crypto unavailable', e ? void 0 : crypto) + : (j = !1)) + : (j = !1) + : z && x(2, n + d, e)), + (r[n] = j), + l((n = 'MODULO_MODE')) && V(e, 0, 9, 2, n) && (H = 0 | e), + (r[n] = H), + l((n = 'POW_PRECISION')) && V(e, 0, S, 2, n) && (W = 0 | e), + (r[n] = W), + l((n = 'FORMAT')) && + ('object' == typeof e + ? (J = e) + : z && x(2, n + ' not an object', e)), + (r[n] = J), + r + ); + }), + (a.max = function() { + return D(arguments, M.lt); + }), + (a.min = function() { + return D(arguments, M.gt); + }), + (a.random = (function() { + var e = 9007199254740992, + n = + (Math.random() * e) & 2097151 + ? function() { + return p(Math.random() * e); + } + : function() { + return ( + 8388608 * ((1073741824 * Math.random()) | 0) + + ((8388608 * Math.random()) | 0) + ); + }; + return function(e) { + var t, + r, + i, + o, + u, + s = 0, + l = [], + f = new a(T); + if ( + ((e = null != e && V(e, 0, S, 14) ? 0 | e : B), (o = g(e / b)), j) + ) + if (crypto.getRandomValues) { + for ( + t = crypto.getRandomValues(new Uint32Array((o *= 2))); + o > s; + + ) + (u = 131072 * t[s] + (t[s + 1] >>> 11)), + u >= 9e15 + ? ((r = crypto.getRandomValues(new Uint32Array(2))), + (t[s] = r[0]), + (t[s + 1] = r[1])) + : (l.push(u % 1e14), (s += 2)); + s = o / 2; + } else if (crypto.randomBytes) { + for (t = crypto.randomBytes((o *= 7)); o > s; ) + (u = + 281474976710656 * (31 & t[s]) + + 1099511627776 * t[s + 1] + + 4294967296 * t[s + 2] + + 16777216 * t[s + 3] + + (t[s + 4] << 16) + + (t[s + 5] << 8) + + t[s + 6]), + u >= 9e15 + ? crypto.randomBytes(7).copy(t, s) + : (l.push(u % 1e14), (s += 7)); + s = o / 7; + } else (j = !1), z && x(14, 'crypto unavailable', crypto); + if (!j) for (; o > s; ) (u = n()), 9e15 > u && (l[s++] = u % 1e14); + for ( + o = l[--s], + e %= b, + o && e && ((u = O[b - e]), (l[s] = p(o / u) * u)); + 0 === l[s]; + l.pop(), s-- + ); + if (0 > s) l = [(i = 0)]; + else { + for (i = -1; 0 === l[0]; l.shift(), i -= b); + for (s = 1, u = l[0]; u >= 10; u /= 10, s++); + b > s && (i -= b - s); + } + return (f.e = i), (f.c = l), f; + }; + })()), + (L = (function() { + function e(e, n, t) { + var r, + i, + o, + u, + s = 0, + l = e.length, + f = n % R, + c = (n / R) | 0; + for (e = e.slice(); l--; ) + (o = e[l] % R), + (u = (e[l] / R) | 0), + (r = c * o + u * f), + (i = f * o + (r % R) * R + s), + (s = ((i / t) | 0) + ((r / R) | 0) + c * u), + (e[l] = i % t); + return s && e.unshift(s), e; + } + function n(e, n, t, r) { + var i, o; + if (t != r) o = t > r ? 1 : -1; + else + for (i = o = 0; t > i; i++) + if (e[i] != n[i]) { + o = e[i] > n[i] ? 1 : -1; + break; + } + return o; + } + function r(e, n, t, r) { + for (var i = 0; t--; ) + (e[t] -= i), + (i = e[t] < n[t] ? 1 : 0), + (e[t] = i * r + e[t] - n[t]); + for (; !e[0] && e.length > 1; e.shift()); + } + return function(i, o, u, s, l) { + var f, + c, + h, + g, + d, + m, + w, + v, + y, + O, + R, + S, + A, + E, + D, + F, + _, + x = i.s == o.s ? 1 : -1, + L = i.c, + U = o.c; + if (!(L && L[0] && U && U[0])) + return new a( + i.s && o.s && (L ? !U || L[0] != U[0] : U) + ? (L && 0 == L[0]) || !U ? 0 * x : x / 0 + : NaN + ); + for ( + v = new a(x), + y = v.c = [], + c = i.e - o.e, + x = u + c + 1, + l || + ((l = N), (c = t(i.e / b) - t(o.e / b)), (x = (x / b) | 0)), + h = 0; + U[h] == (L[h] || 0); + h++ + ); + if ((U[h] > (L[h] || 0) && c--, 0 > x)) y.push(1), (g = !0); + else { + for ( + E = L.length, + F = U.length, + h = 0, + x += 2, + d = p(l / (U[0] + 1)), + d > 1 && + ((U = e(U, d, l)), + (L = e(L, d, l)), + (F = U.length), + (E = L.length)), + A = F, + O = L.slice(0, F), + R = O.length; + F > R; + O[R++] = 0 + ); + (_ = U.slice()), _.unshift(0), (D = U[0]), U[1] >= l / 2 && D++; + do { + if (((d = 0), (f = n(U, O, F, R)), 0 > f)) { + if ( + ((S = O[0]), + F != R && (S = S * l + (O[1] || 0)), + (d = p(S / D)), + d > 1) + ) + for ( + d >= l && (d = l - 1), + m = e(U, d, l), + w = m.length, + R = O.length; + 1 == n(m, O, w, R); + + ) + d--, r(m, w > F ? _ : U, w, l), (w = m.length), (f = 1); + else 0 == d && (f = d = 1), (m = U.slice()), (w = m.length); + if ( + (R > w && m.unshift(0), + r(O, m, R, l), + (R = O.length), + -1 == f) + ) + for (; n(U, O, F, R) < 1; ) + d++, r(O, R > F ? _ : U, R, l), (R = O.length); + } else 0 === f && (d++, (O = [0])); + (y[h++] = d), + O[0] ? (O[R++] = L[A] || 0) : ((O = [L[A]]), (R = 1)); + } while ((A++ < E || null != O[0]) && x--); + (g = null != O[0]), y[0] || y.shift(); + } + if (l == N) { + for (h = 1, x = y[0]; x >= 10; x /= 10, h++); + I(v, u + (v.e = h + c * b - 1) + 1, s, g); + } else (v.e = c), (v.r = +g); + return v; + }; + })()), + (U = (function() { + var e = /^(-?)0([xbo])(?=\w[\w.]*$)/i, + n = /^([^.]+)\.$/, + t = /^\.([^.]+)$/, + r = /^-?(Infinity|NaN)$/, + i = /^\s*\+(?=[\w.])|^\s+|\s+$/g; + return function(o, u, s, l) { + var f, + c = s ? u : u.replace(i, ''); + if (r.test(c)) o.s = isNaN(c) ? null : 0 > c ? -1 : 1; + else { + if ( + !s && + ((c = c.replace(e, function(e, n, t) { + return ( + (f = 'x' == (t = t.toLowerCase()) ? 16 : 'b' == t ? 2 : 8), + l && l != f ? e : n + ); + })), + l && ((f = l), (c = c.replace(n, '$1').replace(t, '0.$1'))), + u != c) + ) + return new a(c, f); + z && x(C, 'not a' + (l ? ' base ' + l : '') + ' number', u), + (o.s = null); + } + (o.c = o.e = null), (C = 0); + }; + })()), + (M.absoluteValue = M.abs = function() { + var e = new a(this); + return e.s < 0 && (e.s = 1), e; + }), + (M.ceil = function() { + return I(new a(this), this.e + 1, 2); + }), + (M.comparedTo = M.cmp = function(e, n) { + return (C = 1), i(this, new a(e, n)); + }), + (M.decimalPlaces = M.dp = function() { + var e, + n, + r = this.c; + if (!r) return null; + if (((e = ((n = r.length - 1) - t(this.e / b)) * b), (n = r[n]))) + for (; n % 10 == 0; n /= 10, e--); + return 0 > e && (e = 0), e; + }), + (M.dividedBy = M.div = function(e, n) { + return (C = 3), L(this, new a(e, n), B, P); + }), + (M.dividedToIntegerBy = M.divToInt = function(e, n) { + return (C = 4), L(this, new a(e, n), 0, 1); + }), + (M.equals = M.eq = function(e, n) { + return (C = 5), 0 === i(this, new a(e, n)); + }), + (M.floor = function() { + return I(new a(this), this.e + 1, 3); + }), + (M.greaterThan = M.gt = function(e, n) { + return (C = 6), i(this, new a(e, n)) > 0; + }), + (M.greaterThanOrEqualTo = M.gte = function(e, n) { + return (C = 7), 1 === (n = i(this, new a(e, n))) || 0 === n; + }), + (M.isFinite = function() { + return !!this.c; + }), + (M.isInteger = M.isInt = function() { + return !!this.c && t(this.e / b) > this.c.length - 2; + }), + (M.isNaN = function() { + return !this.s; + }), + (M.isNegative = M.isNeg = function() { + return this.s < 0; + }), + (M.isZero = function() { + return !!this.c && 0 == this.c[0]; + }), + (M.lessThan = M.lt = function(e, n) { + return (C = 8), i(this, new a(e, n)) < 0; + }), + (M.lessThanOrEqualTo = M.lte = function(e, n) { + return (C = 9), -1 === (n = i(this, new a(e, n))) || 0 === n; + }), + (M.minus = M.sub = function(e, n) { + var r, + i, + o, + u, + s = this, + l = s.s; + if (((C = 10), (e = new a(e, n)), (n = e.s), !l || !n)) + return new a(NaN); + if (l != n) return (e.s = -n), s.plus(e); + var f = s.e / b, + c = e.e / b, + h = s.c, + g = e.c; + if (!f || !c) { + if (!h || !g) return h ? ((e.s = -n), e) : new a(g ? s : NaN); + if (!h[0] || !g[0]) + return g[0] ? ((e.s = -n), e) : new a(h[0] ? s : 3 == P ? -0 : 0); + } + if (((f = t(f)), (c = t(c)), (h = h.slice()), (l = f - c))) { + for ( + (u = 0 > l) ? ((l = -l), (o = h)) : ((c = f), (o = g)), + o.reverse(), + n = l; + n--; + o.push(0) + ); + o.reverse(); + } else + for ( + i = (u = (l = h.length) < (n = g.length)) ? l : n, l = n = 0; + i > n; + n++ + ) + if (h[n] != g[n]) { + u = h[n] < g[n]; + break; + } + if ( + (u && ((o = h), (h = g), (g = o), (e.s = -e.s)), + (n = (i = g.length) - (r = h.length)), + n > 0) + ) + for (; n--; h[r++] = 0); + for (n = N - 1; i > l; ) { + if (h[--i] < g[i]) { + for (r = i; r && !h[--r]; h[r] = n); + --h[r], (h[i] += N); + } + h[i] -= g[i]; + } + for (; 0 == h[0]; h.shift(), --c); + return h[0] + ? _(e, h, c) + : ((e.s = 3 == P ? -1 : 1), (e.c = [(e.e = 0)]), e); + }), + (M.modulo = M.mod = function(e, n) { + var t, + r, + i = this; + return ( + (C = 11), + (e = new a(e, n)), + !i.c || !e.s || (e.c && !e.c[0]) + ? new a(NaN) + : !e.c || (i.c && !i.c[0]) + ? new a(i) + : (9 == H + ? ((r = e.s), + (e.s = 1), + (t = L(i, e, 0, 3)), + (e.s = r), + (t.s *= r)) + : (t = L(i, e, 0, H)), + i.minus(t.times(e))) + ); + }), + (M.negated = M.neg = function() { + var e = new a(this); + return (e.s = -e.s || null), e; + }), + (M.plus = M.add = function(e, n) { + var r, + i = this, + o = i.s; + if (((C = 12), (e = new a(e, n)), (n = e.s), !o || !n)) + return new a(NaN); + if (o != n) return (e.s = -n), i.minus(e); + var u = i.e / b, + s = e.e / b, + l = i.c, + f = e.c; + if (!u || !s) { + if (!l || !f) return new a(o / 0); + if (!l[0] || !f[0]) return f[0] ? e : new a(l[0] ? i : 0 * o); + } + if (((u = t(u)), (s = t(s)), (l = l.slice()), (o = u - s))) { + for ( + o > 0 ? ((s = u), (r = f)) : ((o = -o), (r = l)), r.reverse(); + o--; + r.push(0) + ); + r.reverse(); + } + for ( + o = l.length, + n = f.length, + 0 > o - n && ((r = f), (f = l), (l = r), (n = o)), + o = 0; + n; + + ) + (o = ((l[--n] = l[n] + f[n] + o) / N) | 0), + (l[n] = N === l[n] ? 0 : l[n] % N); + return o && (l.unshift(o), ++s), _(e, l, s); + }), + (M.precision = M.sd = function(e) { + var n, + t, + r = this, + i = r.c; + if ( + (null != e && + e !== !!e && + 1 !== e && + 0 !== e && + (z && x(13, 'argument' + d, e), e != !!e && (e = null)), + !i) + ) + return null; + if (((t = i.length - 1), (n = t * b + 1), (t = i[t]))) { + for (; t % 10 == 0; t /= 10, n--); + for (t = i[0]; t >= 10; t /= 10, n++); + } + return e && r.e + 1 > n && (n = r.e + 1), n; + }), + (M.round = function(e, n) { + var t = new a(this); + return ( + (null == e || V(e, 0, S, 15)) && + I( + t, + ~~e + this.e + 1, + null != n && V(n, 0, 8, 15, m) ? 0 | n : P + ), + t + ); + }), + (M.shift = function(e) { + var n = this; + return V(e, -y, y, 16, 'argument') + ? n.times('1e' + c(e)) + : new a( + n.c && n.c[0] && (-y > e || e > y) + ? n.s * (0 > e ? 0 : 1 / 0) + : n + ); + }), + (M.squareRoot = M.sqrt = function() { + var e, + n, + i, + o, + u, + s = this, + l = s.c, + f = s.s, + c = s.e, + h = B + 4, + g = new a('0.5'); + if (1 !== f || !l || !l[0]) + return new a(!f || (0 > f && (!l || l[0])) ? NaN : l ? s : 1 / 0); + if ( + ((f = Math.sqrt(+s)), + 0 == f || f == 1 / 0 + ? ((n = r(l)), + (n.length + c) % 2 == 0 && (n += '0'), + (f = Math.sqrt(n)), + (c = t((c + 1) / 2) - (0 > c || c % 2)), + f == 1 / 0 + ? (n = '1e' + c) + : ((n = f.toExponential()), + (n = n.slice(0, n.indexOf('e') + 1) + c)), + (i = new a(n))) + : (i = new a(f + '')), + i.c[0]) + ) + for (c = i.e, f = c + h, 3 > f && (f = 0); ; ) + if ( + ((u = i), + (i = g.times(u.plus(L(s, u, h, 1)))), + r(u.c).slice(0, f) === (n = r(i.c)).slice(0, f)) + ) { + if ( + (i.e < c && --f, + (n = n.slice(f - 3, f + 1)), + '9999' != n && (o || '4999' != n)) + ) { + (!+n || (!+n.slice(1) && '5' == n.charAt(0))) && + (I(i, i.e + B + 2, 1), (e = !i.times(i).eq(s))); + break; + } + if (!o && (I(u, u.e + B + 2, 0), u.times(u).eq(s))) { + i = u; + break; + } + (h += 4), (f += 4), (o = 1); + } + return I(i, i.e + B + 1, P, e); + }), + (M.times = M.mul = function(e, n) { + var r, + i, + o, + u, + s, + l, + f, + c, + h, + g, + p, + d, + m, + w, + v, + y = this, + O = y.c, + S = ((C = 17), (e = new a(e, n))).c; + if (!(O && S && O[0] && S[0])) + return ( + !y.s || !e.s || (O && !O[0] && !S) || (S && !S[0] && !O) + ? (e.c = e.e = e.s = null) + : ((e.s *= y.s), + O && S ? ((e.c = [0]), (e.e = 0)) : (e.c = e.e = null)), + e + ); + for ( + i = t(y.e / b) + t(e.e / b), + e.s *= y.s, + f = O.length, + g = S.length, + g > f && ((m = O), (O = S), (S = m), (o = f), (f = g), (g = o)), + o = f + g, + m = []; + o--; + m.push(0) + ); + for (w = N, v = R, o = g; --o >= 0; ) { + for ( + r = 0, p = S[o] % v, d = (S[o] / v) | 0, s = f, u = o + s; + u > o; + + ) + (c = O[--s] % v), + (h = (O[s] / v) | 0), + (l = d * c + h * p), + (c = p * c + (l % v) * v + m[u] + r), + (r = ((c / w) | 0) + ((l / v) | 0) + d * h), + (m[u--] = c % w); + m[u] = r; + } + return r ? ++i : m.shift(), _(e, m, i); + }), + (M.toDigits = function(e, n) { + var t = new a(this); + return ( + (e = null != e && V(e, 1, S, 18, 'precision') ? 0 | e : null), + (n = null != n && V(n, 0, 8, 18, m) ? 0 | n : P), + e ? I(t, e, n) : t + ); + }), + (M.toExponential = function(e, n) { + return E(this, null != e && V(e, 0, S, 19) ? ~~e + 1 : null, n, 19); + }), + (M.toFixed = function(e, n) { + return E( + this, + null != e && V(e, 0, S, 20) ? ~~e + this.e + 1 : null, + n, + 20 + ); + }), + (M.toFormat = function(e, n) { + var t = E( + this, + null != e && V(e, 0, S, 21) ? ~~e + this.e + 1 : null, + n, + 21 + ); + if (this.c) { + var r, + i = t.split('.'), + o = +J.groupSize, + u = +J.secondaryGroupSize, + s = J.groupSeparator, + l = i[0], + f = i[1], + c = this.s < 0, + a = c ? l.slice(1) : l, + h = a.length; + if ((u && ((r = o), (o = u), (u = r), (h -= r)), o > 0 && h > 0)) { + for (r = h % o || o, l = a.substr(0, r); h > r; r += o) + l += s + a.substr(r, o); + u > 0 && (l += s + a.slice(r)), c && (l = '-' + l); + } + t = f + ? l + + J.decimalSeparator + + ((u = +J.fractionGroupSize) + ? f.replace( + new RegExp('\\d{' + u + '}\\B', 'g'), + '$&' + J.fractionGroupSeparator + ) + : f) + : l; + } + return t; + }), + (M.toFraction = function(e) { + var n, + t, + i, + o, + u, + s, + l, + f, + c, + h = z, + g = this, + p = g.c, + d = new a(T), + m = (t = new a(T)), + w = (l = new a(T)); + if ( + (null != e && + ((z = !1), + (s = new a(e)), + (z = h), + (!(h = s.isInt()) || s.lt(T)) && + (z && + x( + 22, + 'max denominator ' + + (h ? 'out of range' : 'not an integer'), + e + ), + (e = !h && s.c && I(s, s.e + 1, 1).gte(T) ? s : null))), + !p) + ) + return g.toString(); + for ( + c = r(p), + o = d.e = c.length - g.e - 1, + d.c[0] = O[(u = o % b) < 0 ? b + u : u], + e = !e || s.cmp(d) > 0 ? (o > 0 ? d : m) : s, + u = G, + G = 1 / 0, + s = new a(c), + l.c[0] = 0; + (f = L(s, d, 0, 1)), (i = t.plus(f.times(w))), 1 != i.cmp(e); + + ) + (t = w), + (w = i), + (m = l.plus(f.times((i = m)))), + (l = i), + (d = s.minus(f.times((i = d)))), + (s = i); + return ( + (i = L(e.minus(t), w, 0, 1)), + (l = l.plus(i.times(m))), + (t = t.plus(i.times(w))), + (l.s = m.s = g.s), + (o *= 2), + (n = + L(m, w, o, P) + .minus(g) + .abs() + .cmp( + L(l, t, o, P) + .minus(g) + .abs() + ) < 1 + ? [m.toString(), w.toString()] + : [l.toString(), t.toString()]), + (G = u), + n + ); + }), + (M.toNumber = function() { + return +this; + }), + (M.toPower = M.pow = function(e, n) { + var t, + r, + i, + o = p(0 > e ? -e : +e), + u = this; + if ( + (null != n && ((C = 23), (n = new a(n))), + (!V(e, -y, y, 23, 'exponent') && + (!isFinite(e) || + (o > y && (e /= 0)) || + (parseFloat(e) != e && !(e = NaN)))) || + 0 == e) + ) + return (t = Math.pow(+u, e)), new a(n ? t % n : t); + for ( + n + ? e > 1 && u.gt(T) && u.isInt() && n.gt(T) && n.isInt() + ? (u = u.mod(n)) + : ((i = n), (n = null)) + : W && (t = g(W / b + 2)), + r = new a(T); + ; + + ) { + if (o % 2) { + if (((r = r.times(u)), !r.c)) break; + t ? r.c.length > t && (r.c.length = t) : n && (r = r.mod(n)); + } + if (((o = p(o / 2)), !o)) break; + (u = u.times(u)), + t + ? u.c && u.c.length > t && (u.c.length = t) + : n && (u = u.mod(n)); + } + return n + ? r + : (0 > e && (r = T.div(r)), i ? r.mod(i) : t ? I(r, W, P) : r); + }), + (M.toPrecision = function(e, n) { + return E( + this, + null != e && V(e, 1, S, 24, 'precision') ? 0 | e : null, + n, + 24 + ); + }), + (M.toString = function(e) { + var n, + t = this, + i = t.s, + o = t.e; + return ( + null === o + ? i ? ((n = 'Infinity'), 0 > i && (n = '-' + n)) : (n = 'NaN') + : ((n = r(t.c)), + (n = + null != e && V(e, 2, 64, 25, 'base') + ? A(f(n, o), 0 | e, 10, i) + : q >= o || o >= k ? l(n, o) : f(n, o)), + 0 > i && t.c[0] && (n = '-' + n)), + n + ); + }), + (M.truncated = M.trunc = function() { + return I(new a(this), this.e + 1, 1); + }), + (M.valueOf = M.toJSON = function() { + var e, + n = this, + t = n.e; + return null === t + ? n.toString() + : ((e = r(n.c)), + (e = q >= t || t >= k ? l(e, t) : f(e, t)), + n.s < 0 ? '-' + e : e); + }), + (M.isBigNumber = !0), + null != e && a.config(e), + a + ); + } + function t(e) { + var n = 0 | e; + return e > 0 || e === n ? n : n - 1; + } + function r(e) { + for (var n, t, r = 1, i = e.length, o = e[0] + ''; i > r; ) { + for (n = e[r++] + '', t = b - n.length; t--; n = '0' + n); + o += n; + } + for (i = o.length; 48 === o.charCodeAt(--i); ); + return o.slice(0, i + 1 || 1); + } + function i(e, n) { + var t, + r, + i = e.c, + o = n.c, + u = e.s, + s = n.s, + l = e.e, + f = n.e; + if (!u || !s) return null; + if (((t = i && !i[0]), (r = o && !o[0]), t || r)) + return t ? (r ? 0 : -s) : u; + if (u != s) return u; + if (((t = 0 > u), (r = l == f), !i || !o)) return r ? 0 : !i ^ t ? 1 : -1; + if (!r) return (l > f) ^ t ? 1 : -1; + for (s = (l = i.length) < (f = o.length) ? l : f, u = 0; s > u; u++) + if (i[u] != o[u]) return (i[u] > o[u]) ^ t ? 1 : -1; + return l == f ? 0 : (l > f) ^ t ? 1 : -1; + } + function o(e, n, t) { + return (e = c(e)) >= n && t >= e; + } + function u(e) { + return '[object Array]' == Object.prototype.toString.call(e); + } + function s(e, n, t) { + for (var r, i, o = [0], u = 0, s = e.length; s > u; ) { + for (i = o.length; i--; o[i] *= n); + for (o[(r = 0)] += v.indexOf(e.charAt(u++)); r < o.length; r++) + o[r] > t - 1 && + (null == o[r + 1] && (o[r + 1] = 0), + (o[r + 1] += (o[r] / t) | 0), + (o[r] %= t)); + } + return o.reverse(); + } + function l(e, n) { + return ( + (e.length > 1 ? e.charAt(0) + '.' + e.slice(1) : e) + + (0 > n ? 'e' : 'e+') + + n + ); + } + function f(e, n) { + var t, r; + if (0 > n) { + for (r = '0.'; ++n; r += '0'); + e = r + e; + } else if (((t = e.length), ++n > t)) { + for (r = '0', n -= t; --n; r += '0'); + e += r; + } else t > n && (e = e.slice(0, n) + '.' + e.slice(n)); + return e; + } + function c(e) { + return (e = parseFloat(e)), 0 > e ? g(e) : p(e); + } + var a, + h = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i, + g = Math.ceil, + p = Math.floor, + d = ' not a boolean or binary digit', + m = 'rounding mode', + w = 'number type has more than 15 significant digits', + v = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_', + N = 1e14, + b = 14, + y = 9007199254740991, + O = [ + 1, + 10, + 100, + 1e3, + 1e4, + 1e5, + 1e6, + 1e7, + 1e8, + 1e9, + 1e10, + 1e11, + 1e12, + 1e13 + ], + R = 1e7, + S = 1e9; + (a = n()), + (a['default'] = a.BigNumber = a), + 'function' == typeof define && define.amd + ? define(function() { + return a; + }) + : 'undefined' != typeof module && module.exports + ? (module.exports = a) + : (e || + (e = + 'undefined' != typeof self ? self : Function('return this')()), + (e.BigNumber = a)); + })(this); + //# sourceMappingURL=bignumber.js.map + + window.BigNumber = BigNumber; +})(); diff --git a/modules/preloader/injected/EthereumProvider.js b/modules/preloader/injected/EthereumProvider.js new file mode 100644 index 0000000..c359a8a --- /dev/null +++ b/modules/preloader/injected/EthereumProvider.js @@ -0,0 +1,191 @@ +(function() { + var EventEmitter = window.EventEmitter; + + var postMessage = function(payload) { + if (typeof payload === 'object') { + payload = JSON.stringify(payload); + } + + window.postMessage( + payload, + !location.origin || location.origin === 'null' ? '*' : location.origin + ); + }; + + // on events are: "connect", "data", "error", "end", "timeout" + // "data" will get notifications + + function EthereumProvider() { + var _this = this; + // Call constructor of superclass to initialize superclass-derived members. + EventEmitter.call(this); + + this.responseCallbacks = {}; + + // fire the connect + this._connect(); + this._reconnectCheck(); + + // Wait for response messages + window.addEventListener('message', function(event) { + var data; + try { + data = JSON.parse(event.data); + } catch (e) { + data = event.data; + } + + if ( + typeof data !== 'object' || + (data.message && + (!Object.prototype.hasOwnProperty.call(data.message, 'jsonrpc') && + !Object.prototype.hasOwnProperty.call(data.message[0], 'jsonrpc'))) + ) { + return; + } + + if (data.type === 'data') { + var id = null; + var result = data.message; + + // get the id which matches the returned id + if ( + typeof result === 'object' && + result.forEach && + isFinite(result.length) + ) { + result.forEach(function(load) { + if (_this.responseCallbacks[load.id]) id = load.id; + }); + } else { + id = result.id; + } + + // notification + if ( + !id && + result.method && + result.method.indexOf('_subscription') !== -1 + ) { + // _this.listeners('data').forEach(function(callback){ + // if(typeof callback === 'function') + // callback(null, result); + // }); + _this.emit('data', result); + + // fire the callback + } else if (_this.responseCallbacks[id]) { + _this.responseCallbacks[id](null, result); + delete _this.responseCallbacks[id]; + } + + // make all other events listenable + } else if (data.type) { + // _this.listeners(data.type).forEach(function(callback){ + // if(typeof callback === 'function') + // callback(null, data.message); + // }); + // TODO check if secure + _this.emit('data.type', data.message); + } + }); + } + + EthereumProvider.prototype = Object.create(EventEmitter.prototype); + EthereumProvider.prototype.constructor = EthereumProvider; + + /** + Get the adds a callback to the responseCallbacks object, + which will be called if a response matching the response Id will arrive. + + @method _addResponseCallback + */ + EthereumProvider.prototype._addResponseCallback = function( + payload, + callback + ) { + var id = payload.id || payload[0].id; + var method = payload.method || payload[0].method; + + if (typeof callback !== 'function') { + throw new Error( + 'No callback given, sync calls are not possible anymore in Mist. Please use only async calls.' + ); + } + + this.responseCallbacks[id] = callback; + this.responseCallbacks[id].method = method; + }; + + /** + Will watch for connection drops and tries to reconnect. + + @method _reconnectCheck + */ + EthereumProvider.prototype._reconnectCheck = function() { + var _this = this; + var reconnectIntervalId; + + this.on('end', function() { + reconnectIntervalId = setInterval(function() { + _this._connect(); + }, 500); + }); + + this.on('connect', function() { + clearInterval(reconnectIntervalId); + }); + }; + + /** + Will try to make a connection + + @method connect + */ + EthereumProvider.prototype._connect = function(payload, callback) { + postMessage({ + type: 'create' + }); + }; + + /** + Sends the request + + @method send + @param {Object} payload example: {id: 1, jsonrpc: '2.0', 'method': 'eth_someMethod', params: []} + @param {Function} callback the callback to call + */ + // TODO transform to: send(method, params, callback) + EthereumProvider.prototype.send = function send(payload, callback) { + this._addResponseCallback(payload, callback); + postMessage( + { + type: 'write', + message: payload + }, + this.origin + ); + }; + + delete window.EventEmitter; + // TODO set real ethereum provider + // window.ethereum = new EthereumProvider(); + + // For backwards compatibility of web3.currentProvider; + EthereumProvider.prototype.sendSync = function() { + return { + jsonrpc: '2.0', + error: { + code: -32603, + message: 'Sync calls are not anymore supported in Mist :\\' + } + }; + }; + EthereumProvider.prototype.sendAsync = EthereumProvider.prototype.send; + EthereumProvider.prototype.isConnected = function() { + return true; + }; + window.web3 = { + currentProvider: new EthereumProvider() + }; +})(); diff --git a/modules/preloader/injected/EventEmitter3.js b/modules/preloader/injected/EventEmitter3.js new file mode 100644 index 0000000..d488300 --- /dev/null +++ b/modules/preloader/injected/EventEmitter3.js @@ -0,0 +1,340 @@ +(function() { + 'use strict'; + + var has = Object.prototype.hasOwnProperty, + prefix = '~'; + + /** + * Constructor to create a storage for our `EE` objects. + * An `Events` instance is a plain object whose properties are event names. + * + * @constructor + * @api private + */ + function Events() {} + + // + // We try to not inherit from `Object.prototype`. In some engines creating an + // instance in this way is faster than calling `Object.create(null)` directly. + // If `Object.create(null)` is not supported we prefix the event names with a + // character to make sure that the built-in object properties are not + // overridden or used as an attack vector. + // + if (Object.create) { + Events.prototype = Object.create(null); + + // + // This hack is needed because the `__proto__` property is still inherited in + // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5. + // + if (!new Events().__proto__) prefix = false; + } + + /** + * Representation of a single event listener. + * + * @param {Function} fn The listener function. + * @param {Mixed} context The context to invoke the listener with. + * @param {Boolean} [once=false] Specify if the listener is a one-time listener. + * @constructor + * @api private + */ + function EE(fn, context, once) { + this.fn = fn; + this.context = context; + this.once = once || false; + } + + /** + * Minimal `EventEmitter` interface that is molded against the Node.js + * `EventEmitter` interface. + * + * @constructor + * @api public + */ + function EventEmitter() { + this._events = new Events(); + this._eventsCount = 0; + } + + /** + * Return an array listing the events for which the emitter has registered + * listeners. + * + * @returns {Array} + * @api public + */ + EventEmitter.prototype.eventNames = function eventNames() { + var names = [], + events, + name; + + if (this._eventsCount === 0) return names; + + for (name in (events = this._events)) { + if (has.call(events, name)) names.push(prefix ? name.slice(1) : name); + } + + if (Object.getOwnPropertySymbols) { + return names.concat(Object.getOwnPropertySymbols(events)); + } + + return names; + }; + + /** + * Return the listeners registered for a given event. + * + * @param {String|Symbol} event The event name. + * @param {Boolean} exists Only check if there are listeners. + * @returns {Array|Boolean} + * @api public + */ + EventEmitter.prototype.listeners = function listeners(event, exists) { + var evt = prefix ? prefix + event : event, + available = this._events[evt]; + + if (exists) return !!available; + if (!available) return []; + if (available.fn) return [available.fn]; + + for (var i = 0, l = available.length, ee = new Array(l); i < l; i++) { + ee[i] = available[i].fn; + } + + return ee; + }; + + /** + * Calls each of the listeners registered for a given event. + * + * @param {String|Symbol} event The event name. + * @returns {Boolean} `true` if the event had listeners, else `false`. + * @api public + */ + EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { + var evt = prefix ? prefix + event : event; + + if (!this._events[evt]) return false; + + var listeners = this._events[evt], + len = arguments.length, + args, + i; + + if (listeners.fn) { + if (listeners.once) + this.removeListener(event, listeners.fn, undefined, true); + + switch (len) { + case 1: + return listeners.fn.call(listeners.context), true; + case 2: + return listeners.fn.call(listeners.context, a1), true; + case 3: + return listeners.fn.call(listeners.context, a1, a2), true; + case 4: + return listeners.fn.call(listeners.context, a1, a2, a3), true; + case 5: + return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; + case 6: + return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; + } + + for (i = 1, args = new Array(len - 1); i < len; i++) { + args[i - 1] = arguments[i]; + } + + listeners.fn.apply(listeners.context, args); + } else { + var length = listeners.length, + j; + + for (i = 0; i < length; i++) { + if (listeners[i].once) + this.removeListener(event, listeners[i].fn, undefined, true); + + switch (len) { + case 1: + listeners[i].fn.call(listeners[i].context); + break; + case 2: + listeners[i].fn.call(listeners[i].context, a1); + break; + case 3: + listeners[i].fn.call(listeners[i].context, a1, a2); + break; + case 4: + listeners[i].fn.call(listeners[i].context, a1, a2, a3); + break; + default: + if (!args) + for (j = 1, args = new Array(len - 1); j < len; j++) { + args[j - 1] = arguments[j]; + } + + listeners[i].fn.apply(listeners[i].context, args); + } + } + } + + return true; + }; + + /** + * Add a listener for a given event. + * + * @param {String|Symbol} event The event name. + * @param {Function} fn The listener function. + * @param {Mixed} [context=this] The context to invoke the listener with. + * @returns {EventEmitter} `this`. + * @api public + */ + EventEmitter.prototype.on = function on(event, fn, context) { + var listener = new EE(fn, context || this), + evt = prefix ? prefix + event : event; + + if (!this._events[evt]) (this._events[evt] = listener), this._eventsCount++; + else if (!this._events[evt].fn) this._events[evt].push(listener); + else this._events[evt] = [this._events[evt], listener]; + + return this; + }; + + /** + * Add a one-time listener for a given event. + * + * @param {String|Symbol} event The event name. + * @param {Function} fn The listener function. + * @param {Mixed} [context=this] The context to invoke the listener with. + * @returns {EventEmitter} `this`. + * @api public + */ + EventEmitter.prototype.once = function once(event, fn, context) { + var listener = new EE(fn, context || this, true), + evt = prefix ? prefix + event : event; + + if (!this._events[evt]) (this._events[evt] = listener), this._eventsCount++; + else if (!this._events[evt].fn) this._events[evt].push(listener); + else this._events[evt] = [this._events[evt], listener]; + + return this; + }; + + /** + * Remove the listeners of a given event. + * + * @param {String|Symbol} event The event name. + * @param {Function} fn Only remove the listeners that match this function. + * @param {Mixed} context Only remove the listeners that have this context. + * @param {Boolean} once Only remove one-time listeners. + * @returns {EventEmitter} `this`. + * @api public + */ + EventEmitter.prototype.removeListener = function removeListener( + event, + fn, + context, + once + ) { + var evt = prefix ? prefix + event : event; + + if (!this._events[evt]) return this; + if (!fn) { + if (--this._eventsCount === 0) this._events = new Events(); + else delete this._events[evt]; + return this; + } + + var listeners = this._events[evt]; + + if (listeners.fn) { + if ( + listeners.fn === fn && + (!once || listeners.once) && + (!context || listeners.context === context) + ) { + if (--this._eventsCount === 0) this._events = new Events(); + else delete this._events[evt]; + } + } else { + for (var i = 0, events = [], length = listeners.length; i < length; i++) { + if ( + listeners[i].fn !== fn || + (once && !listeners[i].once) || + (context && listeners[i].context !== context) + ) { + events.push(listeners[i]); + } + } + + // + // Reset the array, or remove it completely if we have no more listeners. + // + if (events.length) + this._events[evt] = events.length === 1 ? events[0] : events; + else if (--this._eventsCount === 0) this._events = new Events(); + else delete this._events[evt]; + } + + return this; + }; + + /** + * Remove all listeners, or those of the specified event. + * + * @param {String|Symbol} [event] The event name. + * @returns {EventEmitter} `this`. + * @api public + */ + EventEmitter.prototype.removeAllListeners = function removeAllListeners( + event + ) { + var evt; + + if (event) { + evt = prefix ? prefix + event : event; + if (this._events[evt]) { + if (--this._eventsCount === 0) this._events = new Events(); + else delete this._events[evt]; + } + } else { + this._events = new Events(); + this._eventsCount = 0; + } + + return this; + }; + + // + // Alias methods names because people roll like that. + // + EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + EventEmitter.prototype.addListener = EventEmitter.prototype.on; + + // + // This function doesn't apply anymore. + // + EventEmitter.prototype.setMaxListeners = function setMaxListeners() { + return this; + }; + + // + // Expose the prefix. + // + EventEmitter.prefixed = prefix; + + // + // Allow `EventEmitter` to be imported as module namespace. + // + EventEmitter.EventEmitter = EventEmitter; + + // + // Expose the module. + // + if ('undefined' !== typeof module) { + module.exports = EventEmitter; + } + + window.EventEmitter = EventEmitter; +})(); diff --git a/modules/preloader/injected/mistAPI.js b/modules/preloader/injected/mistAPI.js new file mode 100644 index 0000000..bdd8422 --- /dev/null +++ b/modules/preloader/injected/mistAPI.js @@ -0,0 +1,279 @@ +/** + @module MistAPI + */ + +(function() { + 'use strict'; + + var postMessage = function(payload) { + if (typeof payload === 'object') { + payload = JSON.stringify(payload); + } + + window.postMessage( + payload, + !location.origin || location.origin === 'null' ? '*' : location.origin + ); + }; + + var queue = []; + + const prefix = 'entry_'; + const MIST_SUBMENU_LIMIT = 100; + + // todo: error handling + const filterAdd = function(options) { + if (!(options instanceof Object)) { + return false; + } + + return ['name'].every(e => e in options); + }; + + // filterId the id to only contain a-z A-Z 0-9 + const filterId = function(str) { + const filteredStr = String(str); + let newStr = ''; + if (filteredStr) { + for (let i = 0; i < filteredStr.length; i += 1) { + if (/[a-zA-Z0-9_-]/.test(filteredStr.charAt(i))) { + newStr += filteredStr.charAt(i); + } + } + } + return newStr; + }; + + /** + Mist API + + Provides an API for all dapps, which specifically targets features from the Mist browser + + @class mist + @constructor + */ + const mist = { + callbacks: {}, + version: '__version__', + license: '__license__', + platform: '__platform__', + requestAccount(callback) { + if (callback) { + if (!this.callbacks.connectAccount) { + this.callbacks.connectAccount = []; + } + this.callbacks.connectAccount.push(callback); + } + + postMessage({ + type: 'mistAPI_requestAccount' + }); + }, + solidity: { + version: '__solidityVersion__' + }, + sounds: { + bip: function playSound() { + postMessage({ + type: 'mistAPI_sound', + message: 'bip' + }); + }, + bloop: function playSound() { + postMessage({ + type: 'mistAPI_sound', + message: 'bloop' + }); + }, + invite: function playSound() { + postMessage({ + type: 'mistAPI_sound', + message: 'invite' + }); + } + }, + menu: { + entries: {}, + /** + Sets the badge text for the apps menu button + + Example + + mist.menu.setBadge('Some Text') + + @method setBadge + @param {String} text + */ + setBadge(text) { + postMessage({ + type: 'mistAPI_setBadge', + message: text + }); + }, + /** + Adds/Updates a menu entry + + Example + + mist.menu.add('tkrzU', { + name: 'My Meny Entry', + badge: 50, + position: 1, + selected: true + }, function(){ + // Router.go('/chat/1245'); + }) + + @method add + @param {String} id The id of the menu, has to be the same accross page reloads. + @param {Object} options The menu options like {badge: 23, name: 'My Entry'} + @param {Function} callback Change the callback to be called when the menu is pressed. + */ + add(id, options, callback) { + const args = Array.prototype.slice.call(arguments); + callback = + typeof args[args.length - 1] === 'function' ? args.pop() : null; + options = typeof args[args.length - 1] === 'object' ? args.pop() : null; + id = + typeof args[args.length - 1] === 'string' || + isFinite(args[args.length - 1]) + ? args.pop() + : null; + + if (!filterAdd(options)) { + return false; + } + + const filteredId = prefix + filterId(id); + + // restricting to 100 menu entries + if ( + !(filteredId in this.entries) && + Object.keys(this.entries).length >= MIST_SUBMENU_LIMIT + ) { + return false; + } + + const entry = { + id: filteredId || 'mist_defaultId', + position: options.position, + selected: !!options.selected, + name: options.name, + badge: options.badge + }; + + queue.push({ + action: 'addMenu', + entry + }); + + if (callback) { + entry.callback = callback; + } + + this.entries[filteredId] = entry; + return true; + }, + /** + Updates a menu entry from the mist sidebar. + + @method update + @param {String} id The id of the menu, has to be the same accross page reloads. + @param {Object} options The menu options like {badge: 23, name: 'My Entry'} + @param {Function} callback Change the callback to be called when the menu is pressed. + */ + update() { + this.add.apply(this, arguments); + }, + /** + Removes a menu entry from the mist sidebar. + + @method remove + @param {String} id + @param {String} id The id of the menu, has to be the same accross page reloads. + @param {Object} options The menu options like {badge: 23, name: 'My Entry'} + @param {Function} callback Change the callback to be called when the menu is pressed. + */ + remove(id) { + const filteredId = prefix + filterId(id); + + delete this.entries[filteredId]; + + queue.push({ + action: 'removeMenu', + filteredId + }); + }, + /** + Marks a menu entry as selected + + @method select + @param {String} id + */ + select(id) { + const filteredId = prefix + filterId(id); + queue.push({ action: 'selectMenu', id: filteredId }); + + for (const e in this.entries) { + if ({}.hasOwnProperty.call(this.entries, e)) { + this.entries[e].selected = e === filteredId; + } + } + }, + /** + Removes all menu entries. + + @method clear + */ + clear() { + this.entries = {}; + queue.push({ action: 'clearMenu' }); + } + } + }; + + // Wait for response messages + window.addEventListener('message', function(event) { + var data; + try { + data = JSON.parse(event.data); + } catch (e) { + data = event.data; + } + + if (typeof data !== 'object') { + return; + } + + if (data.type === 'mistAPI_callMenuFunction') { + var id = data.message; + + if (mist.menu.entries[id] && mist.menu.entries[id].callback) { + mist.menu.entries[id].callback(); + } + } else if (data.type === 'uiAction_windowMessage') { + var params = data.message; + + if (mist.callbacks[params.type]) { + mist.callbacks[params.type].forEach(function(cb) { + cb(params.error, params.value); + }); + delete mist.callbacks[params.type]; + } + } + }); + + // work up queue every 500ms + setInterval(function() { + if (queue.length > 0) { + postMessage({ + type: 'mistAPI_menuChanges', + message: queue + }); + + queue = []; + } + }, 500); + + window.mist = mist; +})(); diff --git a/modules/preloader/mistUI.js b/modules/preloader/mistUI.js new file mode 100644 index 0000000..b1fdc44 --- /dev/null +++ b/modules/preloader/mistUI.js @@ -0,0 +1,195 @@ +/** +@module preloader MistUI +*/ + +// Initialise the Redux store +window.store = require('./rendererStore'); + +require('./include/common')('mist'); +require('./include/web3CurrentProvider.js'); +const { ipcRenderer, remote, webFrame } = require('electron'); // eslint-disable-line import/newline-after-import +const { Menu, MenuItem } = remote; +const dbSync = require('../dbSync.js'); +const i18n = require('../i18n.js'); +const mist = require('./include/mistAPI.js'); +const web3Admin = require('../web3Admin.js'); + +require('./include/setBasePath')('interface'); + +// add admin later +setTimeout(() => { + web3Admin.extend(window.web3); +}, 1000); + +window.mist = mist(); +window.mistMode = remote.getGlobal('mode'); +window.dbSync = dbSync; +window.dirname = remote.getGlobal('dirname'); +window.ipc = ipcRenderer; + +// remove require and module, because node-integration is on +delete window.module; +delete window.require; + +// prevent overwriting the Dapps Web3 +// delete global.Web3; +// delete window.Web3; + +// set the langauge for the electron interface +// ipcRenderer.send('setLanguage', navigator.language.substr(0,2)); + +// A message coming from other window, to be passed to a webview +ipcRenderer.on('uiAction_windowMessage', (e, type, id, error, value) => { + if (type === 'requestAccount' || (type === 'connectAccount' && !error)) { + Tabs.update( + { webviewId: id }, + { $addToSet: { 'permissions.accounts': value } } + ); + } + + // forward to the webview (TODO: remove and manage in the ipcCommunicator?) + const tab = Tabs.findOne({ webviewId: id }); + if (tab) { + webview = $(`webview[data-id=${tab._id}]`)[0]; + if (webview) { + webview.send('uiAction_windowMessage', type, error, value); + } + } +}); + +ipcRenderer.on('uiAction_enableBlurOverlay', (e, value) => { + $('html').toggleClass('has-blur-overlay', !!value); +}); + +// Wait for webview toggle +ipcRenderer.on('uiAction_toggleWebviewDevTool', (e, id) => { + const webview = Helpers.getWebview(id); + + if (!webview) { + return; + } + + if (webview.isDevToolsOpened()) { + webview.closeDevTools(); + } else { + webview.openDevTools(); + } +}); + +// randomize accounts and drop half +// also certainly remove the web3.ethbase one +const randomizeAccounts = (acc, coinbase) => { + let accounts = _.shuffle(acc); + accounts = _.rest(accounts, (accounts.length / 2).toFixed(0)); + accounts = _.without(accounts, coinbase); + return accounts; +}; + +// Run tests +ipcRenderer.on('uiAction_runTests', (e, type) => { + if (type === 'webview') { + web3.eth.getAccounts((error, accounts) => { + if (error) return; + + web3.eth.getCoinbase((coinbaseError, coinbase) => { + if (coinbaseError) return; + + Tabs.upsert('tests', { + position: -1, + name: 'Tests', + url: '', // is hardcoded in webview.html to prevent hijacking + permissions: { + accounts: randomizeAccounts(accounts, coinbase) + } + }); + + Tracker.afterFlush(() => { + LocalStore.set('selectedTab', 'tests'); + }); + + // update the permissions, when accounts change + Tracker.autorun(() => { + const accountList = _.pluck( + EthAccounts.find({}, { fields: { address: 1 } }).fetch(), + 'address' + ); + + Tabs.update('tests', { + $set: { + 'permissions.accounts': randomizeAccounts(accountList, coinbase) + } + }); + }); + }); + }); + } +}); + +// CONTEXT MENU + +const currentMousePosition = { x: 0, y: 0 }; +const menu = new Menu(); +// menu.append(new MenuItem({ type: 'separator' })); +menu.append( + new MenuItem({ + label: i18n.t('mist.rightClick.reload'), + accelerator: 'Command+R', + click() { + const webview = Helpers.getWebview(LocalStore.get('selectedTab')); + if (webview) { + webview.reloadIgnoringCache(); + } + } + }) +); +menu.append( + new MenuItem({ + label: i18n.t('mist.rightClick.openDevTools'), + click() { + const webview = Helpers.getWebview(LocalStore.get('selectedTab')); + if (webview) { + webview.openDevTools(); + } + } + }) +); +menu.append( + new MenuItem({ + label: i18n.t('mist.rightClick.inspectElements'), + click() { + const webview = Helpers.getWebview(LocalStore.get('selectedTab')); + if (webview) { + webview.inspectElement(currentMousePosition.x, currentMousePosition.y); + } + } + }) +); + +window.addEventListener( + 'contextmenu', + e => { + e.preventDefault(); + + // OPEN CONTEXT MENU over webviews + if ($('webview:hover')[0]) { + currentMousePosition.x = e.layerX; + currentMousePosition.y = e.layerY; + menu.popup(remote.getCurrentWindow()); + } + }, + false +); + +document.addEventListener( + 'keydown', + e => { + // RELOAD current webview + if (e.metaKey && e.keyCode === 82) { + const webview = Helpers.getWebview(LocalStore.get('selectedTab')); + if (webview) { + webview.reloadIgnoringCache(); + } + } + }, + false +); diff --git a/modules/preloader/popupWindows.js b/modules/preloader/popupWindows.js new file mode 100644 index 0000000..8e26a88 --- /dev/null +++ b/modules/preloader/popupWindows.js @@ -0,0 +1,18 @@ +/** +@module preloader PopupWindows +*/ + +require('./popupWindowsNoWeb3.js'); +require('./include/web3CurrentProvider.js'); +const Q = require('bluebird'); +const web3Admin = require('../web3Admin.js'); +const https = require('https'); + +web3Admin.extend(window.web3); + +// make variables globally accessable +window.Q = Q; +window.https = https; + +// Initialise the Redux store +window.store = require('./rendererStore'); diff --git a/modules/preloader/popupWindowsNoWeb3.js b/modules/preloader/popupWindowsNoWeb3.js new file mode 100644 index 0000000..af53dd4 --- /dev/null +++ b/modules/preloader/popupWindowsNoWeb3.js @@ -0,0 +1,24 @@ +/** +@module preloader PopupWindows +*/ + +require('./include/common')('popupWindow'); +const { ipcRenderer, remote, webFrame } = require('electron'); +const mist = require('./include/mistAPI.js'); +const dbSync = require('../dbSync.js'); +require('./include/setBasePath')('interface'); +require('./include/openExternal.js'); + +// receive data in from SendData +ipcRenderer.on('uiAction_sendData', (e, data) => { + Session.set('data', data); +}); + +window.mist = mist(); +window.mistMode = remote.getGlobal('mode'); +window.dirname = remote.getGlobal('dirname'); +window.dbSync = dbSync; +window.ipc = ipcRenderer; + +// Initialise the Redux store +window.store = require('./rendererStore'); diff --git a/modules/preloader/rendererStore.js b/modules/preloader/rendererStore.js new file mode 100644 index 0000000..93842af --- /dev/null +++ b/modules/preloader/rendererStore.js @@ -0,0 +1,20 @@ +// Create the client-side Redux store. +// This store's only purpose is to sync with the main store. +const { createStore, applyMiddleware } = require('redux'); +const { + forwardToMain, + getInitialStateRenderer, + replayActionRenderer +} = require('electron-redux'); +const thunk = require('redux-thunk').default; +const initialState = getInitialStateRenderer(); + +const store = createStore( + () => {}, + initialState, + applyMiddleware(forwardToMain, thunk) +); + +replayActionRenderer(store); + +module.exports = store; diff --git a/modules/preloader/splashScreen.js b/modules/preloader/splashScreen.js new file mode 100644 index 0000000..fada1bb --- /dev/null +++ b/modules/preloader/splashScreen.js @@ -0,0 +1,21 @@ +require('./include/common')('splashscreen'); +require('./include/web3CurrentProvider.js'); +const mist = require('./include/mistAPI.js'); +const { ipcRenderer, remote, webFrame } = require('electron'); + +require('./include/openExternal.js'); +require('./include/setBasePath')('interface'); + +// set appmenu language +ipcRenderer.send('backendAction_getLanguage'); + +// disable pinch zoom +webFrame.setZoomLevelLimits(1, 1); + +window.ipc = ipcRenderer; +window.mist = mist(); +window.mistMode = remote.getGlobal('mode'); +window.dirname = remote.getGlobal('dirname'); + +// Initialise the Redux store +window.store = require('./rendererStore'); diff --git a/modules/preloader/tests.js b/modules/preloader/tests.js new file mode 100644 index 0000000..16ecb7f --- /dev/null +++ b/modules/preloader/tests.js @@ -0,0 +1,22 @@ +/** +@module preloader tests +*/ + +if (location.origin !== 'file://') { + throw new Error('Wrong test file loaded'); +} else { + // load dapp preloader file + require('./dapps.js'); + + const electron = require('electron'); + const ipcRenderer = electron.ipcRenderer; + + window.ipcProvider = require('../ipc/ipcProviderWrapper.js'); + window.permissions = {}; + + ipcRenderer.sendToHost('sendTestData'); + ipcRenderer.on('uiAction_sendTestData', function(e, permissions, coinbase) { + window.permissions = permissions; + window.coinbase = coinbase; + }); +} diff --git a/modules/preloader/walletMain.js b/modules/preloader/walletMain.js new file mode 100644 index 0000000..563df3d --- /dev/null +++ b/modules/preloader/walletMain.js @@ -0,0 +1,25 @@ +/** +@module preloader wallet when loaded in the main window +*/ + +require('./dapps.js'); +require('./include/openExternal.js'); +require('./include/setBasePath')('interface/wallet'); +const { webFrame } = require('electron'); +const web3Admin = require('../web3Admin.js'); + +// make variables globally accessable +// window.dirname = __dirname; + +webFrame.executeJavaScript("window.mistMode = 'wallet';"); + +// add admin later +setTimeout(() => { + web3Admin.extend(window.web3); +}, 1000); + +setTimeout(() => { + if (document.getElementsByTagName('html')[0]) { + document.getElementsByTagName('html')[0].className = window.platform; + } +}, 500); diff --git a/modules/settings.js b/modules/settings.js new file mode 100644 index 0000000..e971d0f --- /dev/null +++ b/modules/settings.js @@ -0,0 +1,497 @@ +const { app } = require('electron'); +const path = require('path'); +const fs = require('fs'); +const packageJson = require('../package.json'); +const _ = require('./utils/underscore'); +const lodash = require('lodash'); + +import { + syncBuildConfig, + syncFlags, + setSwarmEnableOnStart +} from './core/settings/actions'; +import logger from './utils/logger'; + +const settingsLog = logger.create('Settings'); + +let instance = null; + +class Settings { + constructor() { + if (!instance) { + instance = this; + } + + return instance; + } + + init() { + const logLevel = { logLevel: argv.loglevel }; + const logFolder = { logFolder: path.join(this.userDataPath, 'logs') }; + const loggerOptions = Object.assign(argv, logLevel, logFolder); + logger.setup(loggerOptions); + + store.dispatch(syncFlags(argv)); + + // If -v flag provided, log the Mist version and exit + if (argv.version) { + settingsLog.info(`Mist v${this.appVersion}`); + process.exit(0); + } + + // Some Linux installations require this setting: + if (argv.ignoreGpuBlacklist) { + app.commandLine.appendSwitch('ignore-gpu-blacklist', 'true'); + store.dispatch({ type: '[MAIN]:IGNORE_GPU_BLACKLIST:SET' }); + } + + if (this.inAutoTestMode) { + settingsLog.info('AUTOMATED TESTING'); + store.dispatch({ type: '[MAIN]:TEST_MODE:SET' }); + } + + settingsLog.info(`Running in production mode: ${this.inProductionMode}`); + + if (this.rpcMode === 'http') { + settingsLog.warn( + 'Connecting to a node via HTTP instead of ipcMain. This is less secure!!!!'.toUpperCase() + ); + } + + store.dispatch(syncBuildConfig('appVersion', packageJson.version)); + store.dispatch(syncBuildConfig('rpcMode', this.rpcMode)); + store.dispatch(syncBuildConfig('productionMode', this.inProductionMode)); + store.dispatch(syncBuildConfig('uiMode', this.uiMode)); + } + + // @returns "Application Support/Mist" in production mode + // @returns "Application Support/Electron" in development mode + get userDataPath() { + return app.getPath('userData'); + } + + get dbFilePath() { + const dbFileName = this.inAutoTestMode ? 'mist.test.lokidb' : 'mist.lokidb'; + return path.join(this.userDataPath, dbFileName); + } + + get appDataPath() { + // Application Support/ + return app.getPath('appData'); + } + + get userHomePath() { + return app.getPath('home'); + } + + get cli() { + return argv; + } + + get appVersion() { + return packageJson.version; + } + + get appName() { + return this.uiMode === 'mist' ? 'Mist' : 'EtherCore Wallet'; + } + + get appLicense() { + return packageJson.license; + } + + get uiMode() { + return _.isString(argv.mode) ? argv.mode.toLowerCase() : argv.mode; + } + + get inProductionMode() { + return defaultConfig.production; + } + + get inAutoTestMode() { + return !!process.env.TEST_MODE; + } + + get swarmURL() { + return argv.swarmurl; + } + + get gethPath() { + return argv.gethpath; + } + + get ethPath() { + return argv.ethpath; + } + + get rpcMode() { + if (argv.rpc && argv.rpc.indexOf('http') === 0) return 'http'; + if (argv.rpc && argv.rpc.indexOf('ws:') === 0) { + settingsLog.warn( + 'Websockets are not yet supported by Mist, using default IPC connection' + ); + argv.rpc = null; + return 'ipc'; + } else return 'ipc'; + } + + get rpcConnectConfig() { + if (this.rpcMode === 'ipc') { + return { + path: this.rpcIpcPath + }; + } + + return { + hostPort: this.rpcHttpPath + }; + } + + get rpcHttpPath() { + return this.rpcMode === 'http' ? argv.rpc : null; + } + + get rpcIpcPath() { + let ipcPath = this.rpcMode === 'ipc' ? argv.rpc : null; + + if (ipcPath) { + return ipcPath; + } + + ipcPath = this.userHomePath; + + if (process.platform === 'darwin') { + ipcPath += '/Library/EtherCore/geth.ipc'; + } else if ( + process.platform === 'freebsd' || + process.platform === 'linux' || + process.platform === 'sunos' + ) { + ipcPath += '/.ethercore/geth.ipc'; + } else if (process.platform === 'win32') { + ipcPath = '\\\\.\\pipe\\geth.ipc'; + } + + settingsLog.debug(`IPC path: ${ipcPath}`); + + return ipcPath; + } + + get nodeType() { + return argv.node; + } + + get network() { + return argv.network; + } + + get syncmode() { + return argv.syncmode; + } + + get nodeOptions() { + return argv.nodeOptions; + } + + get language() { + return this.loadConfig('ui.i18n'); + } + + set language(langCode) { + this.saveConfig('ui.i18n', langCode); + } + + get enableSwarmOnStart() { + if (global.mode === 'wallet') { + return false; + } + + if (argv.swarm) { + return true; + } + + const enableOnStart = this.loadConfig('swarm.enableOnStart'); + + // Sync to redux + if (enableOnStart) { + store.dispatch(setSwarmEnableOnStart()); + } + + return enableOnStart; + } + + set enableSwarmOnStart(bool) { + this.saveConfig('swarm.enableOnStart', bool); + } + + get skiptimesynccheck() { + return argv.skiptimesynccheck; + } + + initConfig() { + global.config.insert({ + ui: { + i18n: i18n.getBestMatchedLangCode(app.getLocale()) + }, + swarm: { + enableOnStart: argv.swarm + } + }); + } + + saveConfig(key, value) { + let obj = global.config.get(1); + + if (!obj) { + this.initConfig(); + obj = global.config.get(1); + } + + if (lodash.get(obj, key) !== value) { + lodash.set(obj, key, value); + global.config.update(obj); + + settingsLog.debug(`Settings: saveConfig('${key}', '${value}')`); + settingsLog.trace(global.config.data); + } + } + + loadConfig(key) { + const obj = global.config.get(1); + + if (!obj) { + this.initConfig(); + return this.loadConfig(key); + } + + settingsLog.trace( + `Settings: loadConfig('${key}') = '${lodash.get(obj, key)}'` + ); + + return lodash.get(obj, key); + } + + loadUserData(path2) { + const fullPath = this.constructUserDataPath(path2); + + settingsLog.trace('Load user data', fullPath); + + // check if the file exists + try { + fs.accessSync(fullPath, fs.R_OK); + } catch (err) { + return null; + } + + // try to read it + try { + const data = fs.readFileSync(fullPath, { encoding: 'utf8' }); + settingsLog.debug(`Reading "${data}" from ${fullPath}`); + return data; + } catch (err) { + settingsLog.warn(`File not readable: ${fullPath}`, err); + } + + return null; + } + + saveUserData(path2, data) { + if (!data) return; // return so we dont write null, or other invalid data + + const fullPath = this.constructUserDataPath(path2); + + try { + settingsLog.debug(`Saving "${data}" to ${fullPath}`); + fs.writeFileSync(fullPath, data, { encoding: 'utf8' }); + } catch (err) { + settingsLog.warn(`Unable to write to ${fullPath}`, err); + } + } + + constructUserDataPath(filePath) { + return path.join(this.userDataPath, filePath); + } +} + +module.exports = new Settings(); + +/* ========================== +Command line argument parsing +============================= */ + +// Load config +const defaultConfig = { + mode: 'mist', + production: false +}; + +try { + _.extend(defaultConfig, require('../config.json')); +} catch (error) { + settingsLog.error(error); +} + +const argv = require('yargs') + .usage('Usage: $0 [Mist options] [Node options]') + .option({ + mode: { + alias: 'm', + demand: false, + default: defaultConfig.mode, + describe: 'App UI mode: wallet, mist.', + requiresArg: true, + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + node: { + demand: false, + default: null, + describe: 'Node to use: geth, eth', + requiresArg: true, + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + network: { + demand: false, + default: null, + describe: 'Network to connect to: main, test', + requiresArg: true, + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + gcmode: { + demand: false, + default: 'archive', + describe: '--gcmode archive', + requiresArg: true, + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + rpc: { + demand: false, + describe: + 'Path to node IPC socket file OR HTTP RPC hostport (if IPC socket file then --node-ipcpath will be set with this value).', + requiresArg: true, + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + swarm: { + describe: 'Enable Swarm on start.', + requiresArg: false, + nargs: 0, + type: 'boolean', + group: 'Mist options:' + }, + swarmurl: { + demand: false, + default: 'http://localhost:8500', + describe: + 'URL serving the Swarm HTTP API. If null, Mist will open a local node.', + requiresArg: true, + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + gethpath: { + demand: false, + describe: 'Path to Geth executable to use instead of default.', + requiresArg: true, + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + ethpath: { + demand: false, + describe: 'Path to Eth executable to use instead of default.', + requiresArg: true, + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + 'ignore-gpu-blacklist': { + demand: false, + describe: 'Ignores GPU blacklist (needed for some Linux installations).', + requiresArg: false, + nargs: 0, + type: 'boolean', + group: 'Mist options:' + }, + 'reset-tabs': { + demand: false, + describe: 'Reset Mist tabs to their default settings.', + requiresArg: false, + nargs: 0, + type: 'boolean', + group: 'Mist options:' + }, + loglevel: { + demand: false, + default: 'info', + describe: + 'Minimum logging threshold: info, debug, error, trace (shows all logs, including possible passwords over IPC!).', + requiresArg: true, + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + syncmode: { + demand: false, + requiresArg: true, + describe: 'Geth synchronization mode: [fast|light|full]', + nargs: 1, + type: 'string', + group: 'Mist options:' + }, + version: { + alias: 'v', + demand: false, + requiresArg: false, + nargs: 0, + describe: 'Display Mist version.', + group: 'Mist options:', + type: 'boolean' + }, + skiptimesynccheck: { + demand: false, + requiresArg: false, + nargs: 0, + describe: + 'Disable checks for the presence of automatic time sync on your OS.', + group: 'Mist options:', + type: 'boolean' + }, + '': { + describe: + 'To pass options to the underlying node (e.g. Geth) use the --node- prefix, e.g. --node-datadir', + group: 'Node options:' + } + }) + .help('h') + .alias('h', 'help') + .parse(process.argv.slice(1)); + +argv.nodeOptions = []; + +for (const optIdx in argv) { + if (optIdx.indexOf('node-') === 0) { + argv.nodeOptions.push(`--${optIdx.substr(5)}`); + + if (argv[optIdx] !== true) { + argv.nodeOptions.push(argv[optIdx]); + } + } +} + +// some options are shared +if (argv.ipcpath) { + argv.nodeOptions.push('--ipcpath', argv.ipcpath); +} + +if (argv.nodeOptions && argv.nodeOptions.syncmode) { + argv.push('--syncmode', argv.nodeOptions.syncmode); +} diff --git a/modules/socketManager.js b/modules/socketManager.js new file mode 100644 index 0000000..8511916 --- /dev/null +++ b/modules/socketManager.js @@ -0,0 +1,77 @@ +const _ = global._; +const Q = require('bluebird'); +const log = require('./utils/logger').create('Sockets'); + +const Web3IpcSocket = require('./sockets/web3Ipc'); +const Web3HttpSocket = require('./sockets/web3Http'); + +/** + * `Socket` manager. + */ +class SocketManager { + constructor() { + this._sockets = {}; + } + + /** + * Get socket with given id, creating it if it does not exist. + * + * @return {Socket} + */ + create(id, type) { + log.debug(`Create socket, id=${id}, type=${type}`); + + switch (type) { + case 'ipc': + this._sockets[id] = new Web3IpcSocket(this, id); + break; + case 'http': + this._sockets[id] = new Web3HttpSocket(this, id); + break; + default: + throw new Error(`Unrecognized socket type: ${type}`); + } + + return this._sockets[id]; + } + + /** + * Get socket with given id, creating it if it does not exist. + * + * @return {Socket} + */ + get(id, type) { + if (!this._sockets[id]) { + this.create(id, type); + } + + return this._sockets[id]; + } + + /** + * @return {Promise} + */ + destroyAll() { + log.info('Destroy all sockets'); + + return Q.all( + _.map(this._sockets, (s, id) => { + this.remove(id); + return s.destroy(); + }) + ); + } + + /** + * Remove socket with given id from this manager. + * + * Usually called by `Socket` instances when they're destroyed. + */ + remove(id) { + log.debug(`Remove socket, id=${id}`); + + delete this._sockets[id]; + } +} + +module.exports = new SocketManager(); diff --git a/modules/sockets/base.js b/modules/sockets/base.js new file mode 100644 index 0000000..65c9ab0 --- /dev/null +++ b/modules/sockets/base.js @@ -0,0 +1,213 @@ +const _ = global._; +const Q = require('bluebird'); +const EventEmitter = require('events').EventEmitter; + +const log = require('../utils/logger').create('Sockets'); + +const CONNECT_INTERVAL_MS = 1000; +const CONNECT_TIMEOUT_MS = 3000; + +/** + * Socket connecting to Ethereum Node. + */ +class Socket extends EventEmitter { + constructor(socketMgr, id) { + super(); + + this._mgr = socketMgr; + this._id = id; + + this._log = log.create(this._id); + + this._state = null; + } + + get id() { + return this._id; + } + + get isConnected() { + return STATE.CONNECTED === this._state; + } + + /** + * Connect to host. + * @param {Object} connectConfig + * @param {Object} [options] + * @param {Number} [options.timeout] Milliseconds to wait before timeout (default is 5000). + * @return {Promise} + */ + connect(connectConfig, options) { + this._log.info(`Connect to ${JSON.stringify(connectConfig)}`); + + options = _.extend( + { + timeout: CONNECT_TIMEOUT_MS + }, + options + ); + + return this._resetSocket().then(() => { + let connectTimerId = null; + let timeoutTimerId = null; + + this._log.debug('Connecting...'); + + this._log.debug( + `Will wait ${options.timeout}ms for connection to happen.` + ); + + this._state = STATE.CONNECTING; + + return new Q((resolve, reject) => { + this._socket.once('connect', () => { + if (STATE.CONNECTING === this._state) { + this._log.info('Connected!'); + + this._state = STATE.CONNECTED; + + clearTimeout(connectTimerId); + clearTimeout(timeoutTimerId); + + this.emit('connect'); + + resolve(); + } + }); + + this._socket.on('error', err => { + if (STATE.CONNECTING === this._state) { + this._log.warn( + `Connection failed, retrying after ${CONNECT_INTERVAL_MS}ms...` + ); + + connectTimerId = setTimeout(() => { + this._socket.connect(connectConfig); + }, CONNECT_INTERVAL_MS); + } + }); + + timeoutTimerId = setTimeout(() => { + if (STATE.CONNECTING === this._state) { + this._log.error(`Connection failed (${options.timeout}ms elapsed)`); + + this._state = STATE.CONNECTION_TIMEOUT; + + clearTimeout(connectTimerId); + + return reject(new Error('Unable to connect to socket: timeout')); + } + }, options.timeout); + + // initial kick-off + this._socket.connect(connectConfig); + }); + }); + } + + resume() { + this._socket.resume.apply(this, arguments); + } + + pause() { + this._socket.pause.apply(this, arguments); + } + + pipe() { + this._socket.pipe.apply(this, arguments); + } + + /** + * Disconnect from socket. + * @return {Promise} + */ + disconnect(options) { + if (!this._disconnectPromise) { + this._disconnectPromise = new Q((resolve, reject) => { + this._log.info('Disconnecting...'); + + this._state = STATE.DISCONNECTING; + + // remove all existing listeners + this._socket.removeAllListeners(); + + const timer = setTimeout(() => { + log.warn('Disconnection timed out, closing socket anyway...'); + + this._state = STATE.DISCONNECTION_TIMEOUT; + + resolve(); + }, 5000 /* wait 5 seconds for disconnection */); + + this._socket.once('close', () => { + // if we manually killed it then all good + if (STATE.DISCONNECTING === this._state) { + this._log.debug('Disconnected as expected'); + } else { + this._log.warn('Unexpectedly disconnected'); + } + + this._state = STATE.DISCONNECTED; + + clearTimeout(timer); + + resolve(); + }); + + this._socket.destroy(); + }).finally(() => { + this._disconnectPromise = null; + }); + } + + return this._disconnectPromise; + } + + /** + * An alias to `disconnect()`. + * @return {Promise} + */ + destroy() { + this.removeAllListeners(); + return this.disconnect(); + } + + /** + * Write data to socket. + * @param {String} data + */ + write(data) { + if (STATE.CONNECTED !== this._state) { + throw new Error('Socket not connected'); + } + + this._log.trace('Write data', data); + + this._socket.write(data); + } + + /** + * Reset socket. + * + * Upon completion `this._socket` will be set to a valid socket object, but + * not yet connected. + * + * To be implemented by subclasses. + */ + _resetSocket() { + return Q.reject(new Error('Not yet implemented')); + } +} + +exports.Socket = Socket; + +const STATE = (exports.STATE = Socket.STATE = { + CREATED: 0, + CONNECTING: 1, + CONNECTED: 2, + DISCONNECTING: 3, + DISCONNECTED: 4, + ERROR: -1, + DISCONNECTION_TIMEOUT: -2, + CONNECTION_TIMEOUT: -3 +}); diff --git a/modules/sockets/web3Base.js b/modules/sockets/web3Base.js new file mode 100644 index 0000000..8503a0c --- /dev/null +++ b/modules/sockets/web3Base.js @@ -0,0 +1,150 @@ +const _ = global._; +const Q = require('bluebird'); +const oboe = require('oboe'); +const SocketBase = require('./base'); + +const Socket = SocketBase.Socket; +const STATE = SocketBase.STATE; + +module.exports = class Web3Socket extends Socket { + constructor(socketMgr, id) { + super(socketMgr, id); + + this._sendRequests = {}; + + this._handleSocketResponse(); + } + + /** + * Send an RPC call. + * @param {Array|Object} single or array of payloads. + * @param {Object} options Additional options. + * @param {Boolean} [options.fullResult] If set then will return full result + * JSON, not just result value. + * @return {Promise} + */ + send(payload, options) { + return Q.try(() => { + if (!this.isConnected) { + throw new Error('Not connected'); + } + + const isBatch = _.isArray(payload); + + const finalPayload = isBatch + ? _.map(payload, p => this._finalizeSinglePayload(p)) + : this._finalizeSinglePayload(payload); + + /* + For batch requeests we use the id of the first request as the + id to refer to the batch as one. We can do this because the + response will also come back as a batch, in the same order as the + the requests within the batch were sent. + */ + const id = isBatch ? finalPayload[0].id : finalPayload.id; + + this._log.trace(isBatch ? 'Batch request' : 'Request', id, finalPayload); + + this._sendRequests[id] = { + options, + /* Preserve the original id of the request so that we can + update the response with it */ + origId: isBatch ? _.map(payload, p => p.id) : payload.id + }; + + this.write(JSON.stringify(finalPayload)); + + return new Q((resolve, reject) => { + _.extend(this._sendRequests[id], { + resolve, + reject + }); + }); + }); + } + + /** + * Construct a payload object. + * @param {Object} payload Payload to send. + * @param {String} payload.method Method name. + * @param {Object} [payload.params] Method arguments. + * @return {Object} final payload object + */ + _finalizeSinglePayload(payload) { + if (!payload.method) { + throw new Error('Method required'); + } + + return { + jsonrpc: '2.0', + id: _.uuid(), + method: payload.method, + params: payload.params || [] + }; + } + + /** + * Handle responses from Geth. + */ + _handleSocketResponse() { + oboe(this) + .done(result => { + this._log.trace('JSON response', result); + + try { + const isBatch = _.isArray(result); + + const firstItem = isBatch ? result[0] : result; + + const req = firstItem.id ? this._sendRequests[firstItem.id] : null; + + if (req) { + this._log.trace( + isBatch ? 'Batch response' : 'Response', + firstItem.id, + result + ); + + // if we don't want full JSON result, send just the result + if (!_.get(req, 'options.fullResult')) { + if (isBatch) { + result = _.map(result, r => r.result); + } else { + result = result.result; + } + } else { + // restore original ids + if (isBatch) { + req.origId.forEach((id, idx) => { + if (result[idx]) { + result[idx].id = id; + } + }); + } else { + result.id = req.origId; + } + } + + req.resolve({ + isBatch, + result + }); + } else { + // not a response to a request so pass it on as a notification + this.emit('data-notification', result); + } + } catch (err) { + this._log.error('Error handling socket response', err); + } + }) + .fail(err => { + this._log.error('Socket response error', err); + + _.each(this._sendRequests, req => { + req.reject(err); + }); + + this._sendRequests = {}; + }); + } +}; diff --git a/modules/sockets/web3Http.js b/modules/sockets/web3Http.js new file mode 100644 index 0000000..880ef83 --- /dev/null +++ b/modules/sockets/web3Http.js @@ -0,0 +1,128 @@ +const Q = require('bluebird'); +const EventEmitter = require('events').EventEmitter; +const got = require('got'); +const SocketBase = require('./base'); + +const STATE = SocketBase.STATE; + +const Web3SocketBase = require('./web3Base'); + +class HttpSocket extends EventEmitter { + constructor(_parentSocket) { + super(); + + this._log = _parentSocket._log.create('HttpSocket'); + } + + connect(connectConfig) { + this._log.trace('Connect', connectConfig); + + this._hostPort = connectConfig.hostPort; + + const payload = JSON.stringify({ + jsonrpc: '2.0', + id: 0, + method: 'eth_accounts', + params: [] + }); + + this._call(payload) + .then(() => { + this._log.trace('Connection successful'); + + this.emit('connect'); + }) + .catch(err => { + this._log.trace('Connection failed', err); + + this.emit.bind(this, new Error('Unable to connect to HTTP RPC')); + }); + } + + destroy() { + this._log.trace('Destroy'); + + this._hostPort = null; + + this.emit('close'); + } + + write(data) { + this._log.trace('Write data', data); + + this._call(data) + .then(body => { + this._log.trace('Got response', body); + + this.emit('data', body); + }) + .catch(this.emit.bind(this, 'error')); + } + + setEncoding(enc) { + this._log.trace('Set encoding', enc); + + this._encoding = enc; + } + + _call(dataStr) { + return got + .post(this._hostPort, { + encoding: this._encoding, + headers: { + 'Content-Type': 'application/json' + }, + body: dataStr + }) + .then(res => { + return res.body; + }); + } +} + +module.exports = class Web3HttpSocket extends Web3SocketBase { + /** + * Reset socket. + */ + _resetSocket() { + this._log.debug('Resetting socket'); + + return Q.try(() => { + if (STATE.CONNECTED === this._state) { + this._log.debug('Disconnecting prior to reset'); + + return this.disconnect(); + } + }).then(() => { + this._socket = new HttpSocket(this); + + this._socket.setEncoding('utf8'); + + this._socket.on('close', hadError => { + // if we did the disconnection then all good + if (STATE.DISCONNECTING === this._state) { + return; + } + + this.emit('close', hadError); + }); + + this._socket.on('data', data => { + this._log.trace('Got data'); + + this.emit('data', data); + }); + + this._socket.on('error', err => { + // connection errors will be handled in connect() code + if (STATE.CONNECTING === this._state) { + return; + } + + this._log.error(err); + + this.emit('error', err); + }); + }); + } +}; diff --git a/modules/sockets/web3Ipc.js b/modules/sockets/web3Ipc.js new file mode 100644 index 0000000..9fe18df --- /dev/null +++ b/modules/sockets/web3Ipc.js @@ -0,0 +1,68 @@ +const Q = require('bluebird'); +const net = require('net'); +const SocketBase = require('./base'); + +const STATE = SocketBase.STATE; + +const Web3SocketBase = require('./web3Base'); + +module.exports = class Web3IpcSocket extends Web3SocketBase { + /** + * Reset socket. + */ + _resetSocket() { + this._log.debug('Resetting socket'); + + return Q.try(() => { + if (STATE.CONNECTED === this._state) { + this._log.debug('Disconnecting prior to reset'); + + return this.disconnect(); + } + }).then(() => { + this._socket = new net.Socket(); + + this._socket.setTimeout(0); + this._socket.setEncoding('utf8'); + this._socket.unref(); /* allow app to exit even if socket fails to close */ + + this._socket.on('close', hadError => { + // if we did the disconnection then all good + if (STATE.DISCONNECTING === this._state) { + return; + } + + this.emit('close', hadError); + }); + + this._socket.on('end', () => { + this._log.debug('Got "end" event'); + + this.emit('end'); + }); + + this._socket.on('data', data => { + this._log.trace('Got data'); + + this.emit('data', data); + }); + + this._socket.on('timeout', () => { + this._log.trace('Timeout'); + + this.emit('timeout'); + }); + + this._socket.on('error', err => { + // connection errors will be handled in connect() code + if (STATE.CONNECTING === this._state) { + return; + } + + this._log.error(err); + + this.emit('error', err); + }); + }); + } +}; diff --git a/modules/swarmNode.js b/modules/swarmNode.js new file mode 100644 index 0000000..de6da49 --- /dev/null +++ b/modules/swarmNode.js @@ -0,0 +1,117 @@ +const EventEmitter = require('events').EventEmitter; +const Q = require('bluebird'); +const path = require('path'); +const fs = require('fs'); +const os = require('os'); +const clientBinaries = require('./../clientBinaries.json'); + +import Settings from './settings'; +import Swarm from 'swarm-js'; + +let instance = null; + +class SwarmNode extends EventEmitter { + constructor() { + super(); + + if (!instance) { + instance = this; + } + + return instance; + } + + getKeyPath() { + // TODO: replace by web3.utils.randomHex when we use it + function randomHex(bytes) { + let hex = ''; + for (let i = 0; i < bytes * 2; i = i + 1) { + hex += ((Math.random() * 16) | 0).toString(16); + } + return hex; + } + + // Gets Swarm Key path + const swarmKeyDir = path.join(Settings.userDataPath, 'swarmjs'); + const swarmKeyPath = path.join(swarmKeyDir, 'swarmKey'); + + // Generates the key if not there + if (!fs.existsSync(swarmKeyDir)) { + fs.mkdirSync(swarmKeyDir); + } + if (!fs.existsSync(swarmKeyPath)) { + fs.writeFileSync(swarmKeyPath, randomHex(32)); + } + + return swarmKeyPath; + } + + startUsingLocalNode() { + const totalSize = 7406937; // TODO: hardcoded & innacurate, use archives.json instead + let totalDownloaded = 0; + + const swarmBinDir = path.join(Settings.userDataPath, 'swarmjs', 'bin'); + const swarmBinExt = os.platform() === 'win32' ? '.exe' : ''; + const swarmBinPath = path.join(swarmBinDir, `swarm${swarmBinExt}`); + + const config = { + privateKey: this.getKeyPath(), + dataDir: path.join(Settings.userDataPath, 'swarmjs'), + ensApi: Settings.rpcIpcPath, + binPath: swarmBinPath, + onProgress: size => + this.emit('downloadProgress', (totalDownloaded += size) / totalSize), + archives: clientBinaries.swarm.archives + }; + + return new Q((resolve, reject) => { + Swarm.local(config)( + swarm => + new Q(stop => { + this.emit('started', true); + this._stop = stop; + this._swarm = swarm; + resolve(this); + }) + ).catch(reject); + }); + } + + startUsingGateway() { + return new Q((resolve, reject) => { + this.emit('started', false); + this._swarm = Swarm.at(Settings.swarmURL); + this._stop = () => {}; + resolve(this); + }); + } + + init() { + this.emit('starting'); + + if (Settings.swarmURL === 'http://localhost:8500') { + return this.startUsingLocalNode(); + } + return this.startUsingGateway(); + } + + stop() { + if (!this._swarm) { + return Q.reject(new Error('Swarm not initialized, unable to stop.')); + } + + this.emit('stopping'); + this._stop(); + this.emit('stopped'); + } + + upload(arg) { + if (!this._swarm) { + return Q.reject(new Error('Swarm not initialized, unable to upload.')); + } + + return this._swarm.upload(arg); + } +} + +module.exports = new SwarmNode(); diff --git a/modules/updateChecker.js b/modules/updateChecker.js new file mode 100644 index 0000000..29f1784 --- /dev/null +++ b/modules/updateChecker.js @@ -0,0 +1,110 @@ +const _ = global._; +const Windows = require('./windows'); +const Settings = require('./settings'); +const log = require('./utils/logger').create('updateChecker'); +const got = require('got'); +const semver = require('semver'); + +/** + * Check for updates to the app. + * @return {[type]} [description] + */ +const check = (exports.check = () => { + log.info('Check for update...'); + + let str = null; + + switch (Settings.uiMode) { // eslint-disable-line default-case + case 'mist': + str = 'mist'; + break; + case 'wallet': + str = 'wallet'; + break; + } + + return got('https://api.github.com/repos/ethercore/desktop-wallet/releases', { + timeout: 3000, + json: true + }) + .then(res => { + const releases = _.filter(res.body, release => { + return ( + !_.get(release, 'draft') && + _.get(release, 'name', '') + .toLowerCase() + .indexOf(str) >= 0 + ); + }); + + if (!releases.length) { + log.debug('No releases available to check against.'); + + return; + } + + const latest = releases[0]; + + if (semver.gt(latest.tag_name, Settings.appVersion)) { + log.info( + `App (${Settings.appVersion}) is out of date. New ${ + latest.tag_name + } found.` + ); + + return { + name: latest.name, + version: latest.tag_name, + url: latest.html_url + }; + } + + log.info('App is up-to-date.'); + }) + .catch(err => { + log.error('Error checking for update', err); + }); +}); + +function showWindow(options) { + log.debug('Show update checker window'); + + return Windows.createPopup('updateAvailable', options); +} + +exports.run = () => { + check() + .then(update => { + if (update) { + showWindow({ + sendData: { + uiAction_checkUpdateDone: update + } + }); + } + store.dispatch({ type: '[MAIN]:UPDATE_CHECKER:FINISHED' }); + }) + .catch(err => { + log.error(err); + }); +}; + +exports.runVisibly = () => { + const wnd = showWindow({ + sendData: 'uiAction_checkUpdateInProgress' + }); + + wnd.on('ready', () => { + check() + .then(update => { + wnd.send({ + uiAction_checkUpdateDone: update + }); + }) + .catch(err => { + log.error(err); + + wnd.send('uiAction_checkUpdateDone'); + }); + }); +}; diff --git a/modules/utils/logger.js b/modules/utils/logger.js new file mode 100644 index 0000000..4ab0ba1 --- /dev/null +++ b/modules/utils/logger.js @@ -0,0 +1,53 @@ +const _ = require('./underscore'); +import log4js from 'log4js'; + +/** + * Setup logging system. + * @param {Object} [options] + * @param {String} [options.logLevel] Minimum logging threshold (default: info). + * @param {String} [options.logFolder] Log folder to write logs to. + */ +exports.setup = function(options) { + const logFolder = options.logFolder; + const level = options.logLevel || 'info'; + + const config = { + appenders: { + out: { type: 'console' }, + all: { + type: 'file', + filename: `${logFolder}/all.log` + }, + main: { + type: 'file', + filename: `${logFolder}/category/main.log` + }, + EthereumNode: { + type: 'file', + filename: `${logFolder}/category/ethereum_node.log` + }, + swarm: { + type: 'file', + filename: `${logFolder}/category/swarm.log` + } + }, + categories: { + default: { appenders: ['out', 'all', 'main'], level }, + EthereumNode: { appenders: ['out', 'all', 'EthereumNode'], level }, + swarm: { appenders: ['out', 'all', 'swarm'], level } + } + }; + + log4js.configure(config); +}; + +exports.create = category => { + const logger = log4js.getLogger(category); + + // Allow for easy creation of sub-categories. + logger.create = subCategory => { + return exports.create(`${category}/${subCategory}`); + }; + + return logger; +}; diff --git a/modules/utils/underscore.js b/modules/utils/underscore.js new file mode 100644 index 0000000..3231f7b --- /dev/null +++ b/modules/utils/underscore.js @@ -0,0 +1,39 @@ +const _ = (module.exports = require('underscore')); +const uuid = require('uuid'); +const underscoreDeepExtend = require('underscore-deep-extend'); + +_.mixin({ + /** + * Get a deeply nested object property. + * + * @param {Object} obj The object. + * @param {String} path The path within the object to fetch. + * @param {*} fallbackValue The value to return if given path not found. + * + * @return {*} Returns value if found; otherwise the fallbackVAlue. + */ + get(obj, path, fallbackValue) { + if (this.isUndefined(obj) || obj === null || typeof path !== 'string') { + return fallbackValue; + } + + const fields = path.split('.'); + let result = obj; + + for (let i = 0; i < fields.length; ++i) { + if (!this.isObject(result) && !this.isArray(result)) { + return fallbackValue; + } + + result = result[fields[i]]; + } + + return result || fallbackValue; + }, + deepExtend: underscoreDeepExtend(_), + uuid() { + return uuid.v4(); + } +}); + +module.exports = _; diff --git a/modules/web3Admin.js b/modules/web3Admin.js new file mode 100644 index 0000000..3496f24 --- /dev/null +++ b/modules/web3Admin.js @@ -0,0 +1,227 @@ +module.exports = { + extend: web3 => { + function insertMethod(name, call, params, inputFormatter, outputFormatter) { + return new web3._extend.Method({ + name, + call, + params, + inputFormatter, + outputFormatter + }); + } + + function insertProperty(name, getter, outputFormatter) { + return new web3._extend.Property({ name, getter, outputFormatter }); + } + + // ADMIN + web3._extend({ + property: 'admin', + methods: [ + insertMethod( + 'addPeer', + 'admin_addPeer', + 1, + [null], + web3._extend.formatters.formatOutputBool + ), + insertMethod('exportChain', 'admin_exportChain', 1, [null], null), + insertMethod('importChain', 'admin_importChain', 1, [null], null), + insertMethod( + 'verbosity', + 'admin_verbosity', + 1, + [web3._extend.utils.formatInputInt], + web3._extend.formatters.formatOutputBool + ), + insertMethod( + 'setSolc', + 'admin_setSolc', + 1, + [null], + web3._extend.formatters.formatOutputString + ), + insertMethod( + 'startRPC', + 'admin_startRPC', + 4, + [null, web3._extend.utils.formatInputInteger, null, null], + web3._extend.formatters.formatOutputBool + ), + insertMethod( + 'stopRPC', + 'admin_stopRPC', + 0, + [], + web3._extend.formatters.formatOutputBool + ) + ], + properties: [ + insertProperty( + 'nodeInfo', + 'admin_nodeInfo', + web3._extend.formatters.formatOutputString + ), + insertProperty('peers', 'admin_peers', null), + insertProperty( + 'datadir', + 'admin_datadir', + web3._extend.formatters.formatOutputString + ), + insertProperty('chainSyncStatus', 'admin_chainSyncStatus', null) + ] + }); + + // DEBUG + web3._extend({ + property: 'debug', + methods: [ + insertMethod( + 'printBlock', + 'debug_printBlock', + 1, + [web3._extend.formatters.formatInputInt], + web3._extend.formatters.formatOutputString + ), + insertMethod( + 'getBlockRlp', + 'debug_getBlockRlp', + 1, + [web3._extend.formatters.formatInputInt], + web3._extend.formatters.formatOutputString + ), + insertMethod( + 'setHead', + 'debug_setHead', + 1, + [web3._extend.formatters.formatInputInt], + web3._extend.formatters.formatOutputBool + ), + insertMethod( + 'processBlock', + 'debug_processBlock', + 1, + [web3._extend.formatters.formatInputInt], + null + ), + insertMethod( + 'seedHash', + 'debug_seedHash', + 1, + [web3._extend.formatters.formatInputInt], + web3._extend.formatters.formatOutputString + ), + insertMethod( + 'dumpBlock', + 'debug_dumpBlock', + 1, + [web3._extend.formatters.formatInputInt], + null + ) + ], + properties: [] + }); + + // MINER + web3._extend({ + property: 'miner', + methods: [ + insertMethod( + 'start', + 'miner_start', + 1, + [web3._extend.formatters.formatInputInt], + web3._extend.formatters.formatOutputBool + ), + insertMethod( + 'stop', + 'miner_stop', + 1, + [web3._extend.formatters.formatInputInt], + web3._extend.formatters.formatOutputBool + ), + insertMethod( + 'setExtra', + 'miner_setExtra', + 1, + [null], + web3._extend.formatters.formatOutputBool + ), + insertMethod( + 'setGasPrice', + 'miner_setGasPrice', + 1, + [web3._extend.utils.fromDecimal], + web3._extend.formatters.formatOutputBool + ), + insertMethod( + 'startAutoDAG', + 'miner_startAutoDAG', + 0, + [], + web3._extend.formatters.formatOutputBool + ), + insertMethod( + 'stopAutoDAG', + 'miner_stopAutoDAG', + 0, + [], + web3._extend.formatters.formatOutputBool + ), + insertMethod( + 'makeDAG', + 'miner_makeDAG', + 1, + [web3._extend.formatters.inputDefaultBlockNumberFormatter], + web3._extend.formatters.formatOutputBool + ) + ], + properties: [ + insertProperty( + 'hashrate', + 'miner_hashrate', + web3._extend.utils.toDecimal + ) + ] + }); + + // NETWORK + web3._extend({ + property: 'network', + methods: [ + insertMethod( + 'getPeerCount', + 'net_peerCount', + 0, + [], + web3._extend.formatters.formatOutputString + ) + ], + properties: [ + insertProperty( + 'listening', + 'net_listening', + web3._extend.formatters.formatOutputBool + ), + insertProperty( + 'peerCount', + 'net_peerCount', + web3._extend.utils.toDecimal + ), + insertProperty('peers', 'net_peers', null), + insertProperty( + 'version', + 'net_version', + web3._extend.formatters.formatOutputString + ) + ] + }); + + // TX POOL + web3._extend({ + property: 'txpool', + methods: [], + properties: [insertProperty('status', 'txpool_status', null)] + }); + } +}; diff --git a/modules/windows.js b/modules/windows.js new file mode 100644 index 0000000..ea40fe9 --- /dev/null +++ b/modules/windows.js @@ -0,0 +1,676 @@ +const { app, BrowserWindow, ipcMain: ipc } = require('electron'); +const Settings = require('./settings'); +const log = require('./utils/logger').create('Windows'); +const EventEmitter = require('events').EventEmitter; +import { + closeWindow, + openWindow, + resetGenericWindow, + reuseGenericWindow +} from './core/ui/actions'; + +class GenericWindow extends EventEmitter { + constructor(mgr) { + super(); + + this._mgr = mgr; + this._log = log.create('generic'); + this.isPrimary = false; + this.type = 'generic'; + this.isPopup = true; + this.ownerId = null; + this.isAvailable = true; + this.actingType = null; + + this._log.debug('Creating generic window'); + let electronOptions = this._mgr.getDefaultOptionsForType('generic'); + this.window = new BrowserWindow(electronOptions); + + // set Accept_Language header + this.session = this.window.webContents.session; + this.session.setUserAgent(this.session.getUserAgent(), Settings.language); + + this.webContents = this.window.webContents; + this.webContents.once('did-finish-load', () => { + this._log.debug(`Content loaded, id: ${this.id}`); + this.emit('ready'); + }); + + // prevent dropping files + this.webContents.on('will-navigate', e => e.preventDefault()); + + this.window.once('closed', () => { + this._log.debug('Closed'); + this.emit('closed'); + }); + + this.window.on('close', e => { + // Preserve window unless quitting Mist + if (store.getState().ui.appQuit) { + return this.emit('close', e); + } + e.preventDefault(); + this.hide(); + }); + + this.window.on('show', e => this.emit('show', e)); + + this.window.on('hide', e => this.emit('hide', e)); + + this.load(`${global.interfacePopupsUrl}#generic`); + } + + load(url) { + this._log.debug(`Load URL: ${url}`); + this.window.loadURL(url); + } + + send() { + this._log.trace('Sending data', arguments); + this.webContents.send.apply(this.webContents, arguments); + } + + hide() { + this._log.debug('Hide'); + this.window.hide(); + this.send('uiAction_switchTemplate', 'generic'); + this.actingType = null; + this.isAvailable = true; + this.emit('hidden'); + store.dispatch(resetGenericWindow()); + } + + show() { + this._log.debug('Show'); + this.window.show(); + } + + close() { + this._log.debug('Avoiding close of generic window'); + this.hide(); + } + + reuse(type, options, callback) { + this.isAvailable = false; + this.actingType = type; + if (callback) { + this.callback = callback; + } + if (options.ownerId) { + this.ownerId = options.ownerId; + } + if (options.sendData) { + if (_.isString(options.sendData)) { + this.send(options.sendData); + } else if (_.isObject(options.sendData)) { + for (const key in options.sendData) { + if ({}.hasOwnProperty.call(options.sendData, key)) { + this.send(key, options.sendData[key]); + } + } + } + } + this.window.setSize( + options.electronOptions.width, + options.electronOptions.height + ); + this.window.setAlwaysOnTop(true, 'floating', 1); + this.send('uiAction_switchTemplate', type); + this.show(); + store.dispatch(reuseGenericWindow(type)); + } +} + +class Window extends EventEmitter { + constructor(mgr, type, opts) { + super(); + + opts = opts || {}; + + this._mgr = mgr; + this._log = log.create(type); + this.isPrimary = !!opts.primary; + this.type = type; + this.isPopup = !!opts.isPopup; + this.ownerId = opts.ownerId; // the window which creates this new window + + let electronOptions = { + title: Settings.appName, + show: false, + width: 1100, + height: 720, + icon: global.icon, + titleBarStyle: 'hidden-inset', // hidden-inset: more space + backgroundColor: '#F6F6F6', + acceptFirstMouse: true, + darkTheme: true, + webPreferences: { + nodeIntegration: false, + webaudio: true, + webgl: false, + webSecurity: false, // necessary to make routing work on file:// protocol for assets in windows and popups. Not webviews! + textAreasAreResizable: true + } + }; + + electronOptions = _.deepExtend(electronOptions, opts.electronOptions); + + this._log.debug('Creating browser window'); + + this.window = new BrowserWindow(electronOptions); + + // set Accept_Language header + this.session = this.window.webContents.session; + this.session.setUserAgent(this.session.getUserAgent(), Settings.language); + + this.webContents = this.window.webContents; + + this.webContents.once('did-finish-load', () => { + this.isContentReady = true; + + this._log.debug(`Content loaded, id: ${this.id}`); + + if (opts.sendData) { + if (_.isString(opts.sendData)) { + this.send(opts.sendData); + } else if (_.isObject(opts.sendData)) { + for (const key in opts.sendData) { + if ({}.hasOwnProperty.call(opts.sendData, key)) { + this.send(key, opts.sendData[key]); + } + } + } + } + + if (opts.show) { + this.show(); + } + + this.emit('ready'); + }); + + // prevent droping files + this.webContents.on('will-navigate', e => { + e.preventDefault(); + }); + + this.window.once('closed', () => { + this._log.debug('Closed'); + + this.isShown = false; + this.isClosed = true; + this.isContentReady = false; + + this.emit('closed'); + store.dispatch(closeWindow(this.type)); + }); + + this.window.once('close', e => { + this.emit('close', e); + }); + + this.window.on('show', e => { + this.emit('show', e); + }); + + this.window.on('hide', e => { + this.emit('hide', e); + }); + + if (opts.url) { + this.load(opts.url); + } + } + + load(url) { + if (this.isClosed) { + return; + } + + this._log.debug(`Load URL: ${url}`); + + this.window.loadURL(url); + } + + send() { + if (this.isClosed || !this.isContentReady) { + return; + } + + this._log.trace('Sending data', arguments); + + this.webContents.send.apply(this.webContents, arguments); + } + + hide() { + if (this.isClosed) { + return; + } + + this._log.debug('Hide'); + + this.window.hide(); + + this.isShown = false; + } + + show() { + if (this.isClosed) { + return; + } + + this._log.debug('Show'); + + this.window.show(); + + this.isShown = true; + + store.dispatch(openWindow(this.type)); + } + + close() { + if (this.isClosed) { + return; + } + + this._log.debug('Close'); + + this.window.close(); + } +} + +class Windows { + constructor() { + this._windows = {}; + } + + init() { + log.info('Creating commonly-used windows'); + + this.loading = this.create('loading'); + this.generic = this.createGenericWindow(); + + this.loading.on('show', () => { + this.loading.window.center(); + store.dispatch(openWindow('loading')); + }); + + this.loading.on('hide', () => { + store.dispatch(closeWindow('loading')); + }); + + // when a window gets initalized it will send us its id + ipc.on('backendAction_setWindowId', event => { + const id = event.sender.id; + + log.debug('Set window id', id); + + const bwnd = BrowserWindow.fromWebContents(event.sender); + const wnd = _.find(this._windows, w => { + return w.window === bwnd; + }); + + if (wnd) { + log.trace(`Set window id=${id}, type=${wnd.type}`); + + wnd.id = id; + } + }); + + store.dispatch({ type: '[MAIN]:WINDOWS:INIT_FINISH' }); + } + + createGenericWindow() { + const wnd = (this._windows.generic = new GenericWindow(this)); + return wnd; + } + + create(type, opts, callback) { + store.dispatch({ + type: '[MAIN]:WINDOW:CREATE_START', + payload: { type } + }); + + const options = _.deepExtend( + this.getDefaultOptionsForType(type), + opts || {} + ); + + const existing = this.getByType(type); + + if (existing && existing.ownerId === options.ownerId) { + log.debug( + `Window ${type} with owner ${options.ownerId} already existing.` + ); + + return existing; + } + + const category = options.primary ? 'primary' : 'secondary'; + + log.info( + `Create ${category} window: ${type}, owner: ${options.ownerId || + 'notset'}` + ); + + const wnd = (this._windows[type] = new Window(this, type, options)); + wnd.on('closed', this._onWindowClosed.bind(this, wnd)); + + if (callback) { + wnd.callback = callback; + } + + store.dispatch({ + type: '[MAIN]:WINDOW:CREATE_FINISH', + payload: { type } + }); + + return wnd; + } + + getDefaultOptionsForType(type) { + const mainWebPreferences = { + mist: { + nodeIntegration: true /* necessary for webviews; + require will be removed through preloader */, + preload: `${__dirname}/preloader/mistUI.js`, + 'overlay-fullscreen-video': true, + 'overlay-scrollbars': true, + experimentalFeatures: true + }, + wallet: { + preload: `${__dirname}/preloader/walletMain.js`, + 'overlay-fullscreen-video': true, + 'overlay-scrollbars': true + } + }; + + switch (type) { + case 'main': + return { + primary: true, + electronOptions: { + width: Math.max(global.defaultWindow.width, 500), + height: Math.max(global.defaultWindow.height, 440), + x: global.defaultWindow.x, + y: global.defaultWindow.y, + webPreferences: mainWebPreferences[global.mode] + } + }; + case 'splash': + return { + primary: true, + url: `${global.interfacePopupsUrl}#splashScreen_${global.mode}`, + show: true, + electronOptions: { + width: 400, + height: 230, + resizable: false, + backgroundColor: '#F6F6F6', + useContentSize: true, + frame: false, + webPreferences: { + preload: `${__dirname}/preloader/splashScreen.js` + } + } + }; + case 'loading': + return { + show: false, + url: `${global.interfacePopupsUrl}#loadingWindow`, + electronOptions: { + title: '', + alwaysOnTop: true, + resizable: false, + width: 100, + height: 80, + center: true, + frame: false, + useContentSize: true, + titleBarStyle: '', // hidden-inset: more space + skipTaskbar: true, + webPreferences: { + preload: `${__dirname}/preloader/popupWindowsNoWeb3.js` + } + } + }; + case 'about': + return { + url: `${global.interfacePopupsUrl}#about`, + electronOptions: { + width: 420, + height: 230, + alwaysOnTop: true + } + }; + case 'remix': + return { + url: 'https://remix.ethereum.org', + electronOptions: { + width: 1024, + height: 720, + center: true, + frame: true, + resizable: true, + titleBarStyle: 'default' + } + }; + case 'importAccount': + return { + electronOptions: { + width: 600, + height: 370, + alwaysOnTop: true + } + }; + case 'requestAccount': + return { + electronOptions: { + width: 420, + height: 230, + alwaysOnTop: true + } + }; + case 'connectAccount': + return { + electronOptions: { + width: 460, + height: 520, + maximizable: false, + minimizable: false, + alwaysOnTop: true + } + }; + case 'sendTransactionConfirmation': + return { + electronOptions: { + width: 580, + height: 550, + alwaysOnTop: true, + enableLargerThanScreen: false, + resizable: true + } + }; + case 'updateAvailable': + return { + useWeb3: false, + electronOptions: { + width: 580, + height: 250, + alwaysOnTop: true, + resizable: false, + maximizable: false + } + }; + case 'clientUpdateAvailable': + return { + useWeb3: false, + electronOptions: { + width: 600, + height: 340, + alwaysOnTop: false, + resizable: false, + maximizable: false + } + }; + case 'generic': + return { + title: Settings.appName, + show: false, + icon: global.icon, + titleBarStyle: 'hidden-inset', // hidden-inset: more space + backgroundColor: '#F6F6F6', + acceptFirstMouse: true, + darkTheme: true, + webPreferences: { + preload: `${__dirname}/preloader/popupWindows.js`, + nodeIntegration: false, + webaudio: true, + webgl: false, + webSecurity: false, // necessary to make routing work on file:// protocol for assets in windows and popups. Not webviews! + textAreasAreResizable: true + } + }; + } + } + + createPopup(type, options, callback) { + const defaultPopupOpts = { + url: `${global.interfacePopupsUrl}#${type}`, + show: true, + ownerId: null, + useWeb3: true, + electronOptions: { + title: '', + width: 400, + height: 400, + resizable: false, + center: true, + useContentSize: true, + titleBarStyle: 'hidden', // hidden-inset: more space + autoHideMenuBar: true, // TODO: test on windows + webPreferences: { + textAreasAreResizable: false + } + } + }; + + let opts = _.deepExtend( + defaultPopupOpts, + this.getDefaultOptionsForType(type), + options || {} + ); + + // always show on top of main window + const parent = _.find(this._windows, w => { + return w.type === 'main'; + }); + + if (parent) { + opts.electronOptions.parent = parent.window; + } + + // mark it as a pop-up window + opts.isPopup = true; + + if (opts.useWeb3) { + opts.electronOptions.webPreferences.preload = `${__dirname}/preloader/popupWindows.js`; + } else { + opts.electronOptions.webPreferences.preload = `${__dirname}/preloader/popupWindowsNoWeb3.js`; + } + + // If generic window is available, recycle it (unless on blacklist) + const genericWindow = this.getByType('generic'); + const genericWindowBlacklist = [ + 'remix', + 'updateAvailable', + 'connectAccount' + ]; + if ( + !genericWindowBlacklist.includes(type) && + genericWindow && + genericWindow.isAvailable + ) { + genericWindow.reuse(type, opts, callback); + return genericWindow; + } else if (genericWindow) { + // If a generic window exists of the same actingType, focus that window + if (genericWindow.actingType === type) { + genericWindow.webContents.focus(); + return genericWindow; + } + } + + this.loading.show(); + + log.info(`Create popup window: ${type}`); + + const wnd = this.create(type, opts, callback); + + wnd.once('ready', () => { + this.loading.hide(); + }); + + return wnd; + } + + getByType(type) { + log.trace('Get by type', type); + + return _.find(this._windows, w => { + return w.type === type; + }); + } + + getById(id) { + log.trace('Get by id', id); + + return _.find(this._windows, w => { + return w.id === id; + }); + } + + broadcast() { + const data = arguments; + + log.trace('Broadcast', data); + + _.each(this._windows, wnd => { + wnd.send(...data); + }); + } + + /** + * Handle a window being closed. + * + * This will remove the window from the internal list. + * + * This also checks to see if any primary windows are still visible + * (even if hidden). If none found then it quits the app. + * + * @param {Window} wnd + */ + _onWindowClosed(wnd) { + log.debug(`Removing window from list: ${wnd.type}`); + + for (const t in this._windows) { + if (this._windows[t] === wnd) { + delete this._windows[t]; + + break; + } + } + + const anyOpen = _.find(this._windows, wnd => { + return wnd.isPrimary && !wnd.isClosed && wnd.isShown; + }); + + if (!anyOpen) { + log.info('All primary windows closed/invisible, so quitting app...'); + + app.quit(); + } + } +} + +module.exports = new Windows(); diff --git a/package.json b/package.json new file mode 100644 index 0000000..a768442 --- /dev/null +++ b/package.json @@ -0,0 +1,85 @@ +{ + "name": "Mist", + "version": "0.10.0", + "license": "GPL-3.0", + "author": "EtherCore Contributor , Ethereum Mist Team ", + "repository": { + "type": "git", + "url": "https://github.com/ethercore/desktop-wallet.git" + }, + "scripts": { + "postinstall": "electron-builder install-app-deps; cd interface && yarn", + "dev:electron": "electron -r babel-register main.js", + "dev:meteor": "cd interface && meteor --no-release-check", + "dev:tools": "open http://remotedev.io/local/", + "test:basic": "gulp test --test=basic", + "test:unit": "mocha --compilers babel-register tests/unit/**/* --watch", + "test:unit:once": "mocha --compilers babel-register tests/unit/**/*" + }, + "main": "main.js", + "dependencies": { + "bignumber.js": "^4.0.1", + "bluebird": "^3.5.0", + "chai-as-promised": "^6.0.0", + "chai-string": "^1.3.0", + "electron-redux": "^1.3.1", + "electron-window-state": "^4.0.1", + "ethereum-client-binaries": "1.6.4", + "ethereum-keyfile-recognizer": "^1.0.2", + "ethereumjs-abi": "^0.6.3", + "ethereumjs-util": "^5.1.2", + "fs-promise": "^2.0.0", + "got": "^6.7.1", + "i18next": "^7.1.3", + "lodash": "^4.17.4", + "log-rotate": "^0.2.7", + "log4js": "^2.4.1", + "lokijs": "^1.4.3", + "minimongo-standalone": "^1.1.0-3", + "numeral": "^2.0.6", + "oboe": "^2.1.3", + "os-timesync": "^1.0.9", + "redux": "^3.7.2", + "redux-thunk": "^2.2.0", + "remote-redux-devtools": "^0.5.12", + "semver": "^5.1.0", + "solc": "^0.4.18", + "swarm-js": "^0.1.21", + "typescript": "^2.2.2", + "underscore": "^1.8.3", + "underscore-deep-extend": "^1.1.5", + "uuid": "^3.0.1", + "web3": "^0.18.4", + "yargs": "^7.0.2" + }, + "devDependencies": { + "babel-preset-es2016-node5": "^1.1.2", + "babel-register": "^6.26.0", + "chai": "^3.5.0", + "co-mocha": "^1.2.0", + "del": "^3.0.0", + "ecstatic": "^2.1.0", + "electron": "1.8.4", + "electron-builder": "^20.0.8", + "eslint": "^3.14.1", + "eslint-config-airbnb-base": "^11.0.1", + "eslint-plugin-import": "^2.2.0", + "express": "^4.15.3", + "genomatic": "^1.0.0", + "geth-private": "^1.3.0", + "gh-release-assets": "^1.1.0", + "gulp": "4.0.0", + "gulp-babel": "^7.0.0", + "gulp-spawn-mocha": "^3.3.0", + "json-structure-diff": "^0.0.2", + "minimist": "^1.2.0", + "mocha": "^3.2.0", + "redux-mock-store": "^1.3.0", + "require-dir": "^0.3.2", + "run-sequence": "^1.2.1", + "semver-compare": "^1.0.0", + "shelljs": "^0.7.7", + "spectron": "3.8.0", + "xml2js": "^0.4.17" + } +} diff --git a/release.js b/release.js new file mode 100644 index 0000000..63a45e6 --- /dev/null +++ b/release.js @@ -0,0 +1,12 @@ +module.exports = async ( + markdown, + metaData +) => `_Write a brief description of this release._ + +### Checksums + +| File | Checksum (SHA256) | +| ------------ | ----------------- | +| _Asset name_ | _Asset checksum_ | + +${markdown}`; diff --git a/scripts/Locate.nsh b/scripts/Locate.nsh new file mode 100755 index 0000000..a4ed008 --- /dev/null +++ b/scripts/Locate.nsh @@ -0,0 +1,51 @@ +!define locate::Open `!insertmacro locate::Open` + +!macro locate::Open _PATH _OPTIONS _HANDLE + locate::_Open /NOUNLOAD `${_PATH}` `${_OPTIONS}` + Pop ${_HANDLE} +!macroend + + +!define locate::Find `!insertmacro locate::Find` + +!macro locate::Find _HANDLE _PATHANDNAME _PATH _NAME _SIZE _TIME _ATTRIB + locate::_Find /NOUNLOAD `${_HANDLE}` + Pop ${_PATHANDNAME} + Pop ${_PATH} + Pop ${_NAME} + Pop ${_SIZE} + Pop ${_TIME} + Pop ${_ATTRIB} +!macroend + + +!define locate::Close `!insertmacro locate::Close` + +!macro locate::Close _HANDLE + locate::_Close /NOUNLOAD `${_HANDLE}` +!macroend + + +!define locate::GetSize `!insertmacro locate::GetSize` + +!macro locate::GetSize _PATH _OPTIONS _SIZE _FILES _DIRS + locate::_GetSize /NOUNLOAD `${_PATH}` `${_OPTIONS}` + Pop ${_SIZE} + Pop ${_FILES} + Pop ${_DIRS} +!macroend + + +!define locate::RMDirEmpty `!insertmacro locate::RMDirEmpty` + +!macro locate::RMDirEmpty _PATH _OPTIONS _REMOVED + locate::_RMDirEmpty /NOUNLOAD `${_PATH}` `${_OPTIONS}` + Pop ${_REMOVED} +!macroend + + +!define locate::Unload `!insertmacro locate::Unload` + +!macro locate::Unload + locate::_Unload +!macroend diff --git a/scripts/MoveFileFolder.nsh b/scripts/MoveFileFolder.nsh new file mode 100644 index 0000000..dea78c3 --- /dev/null +++ b/scripts/MoveFileFolder.nsh @@ -0,0 +1,256 @@ +;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +; MoveFile and MoveFolder macros +; +; Author: theblazingangel@aol.com (for the AutoPatcher project - www.autopatcher.com) +; Created: June 2007 +;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +;================== +; MoveFile macro +;================== + + !macro MoveFile sourceFile destinationFile + + !define MOVEFILE_JUMP ${__LINE__} + + ; Check source actually exists + + IfFileExists "${sourceFile}" +3 0 + SetErrors + goto done_${MOVEFILE_JUMP} + + ; Add message to details-view/install-log + + DetailPrint "Moving/renaming file: ${sourceFile} to ${destinationFile}" + + ; If destination does not already exists simply move file + + IfFileExists "${destinationFile}" +3 0 + rename "${sourceFile}" "${destinationFile}" + goto done_${MOVEFILE_JUMP} + + ; If overwriting without 'ifnewer' check + + ${If} $switch_overwrite == 1 + delete "${destinationFile}" + rename "${sourceFile}" "${destinationFile}" + delete "${sourceFile}" + goto done_${MOVEFILE_JUMP} + ${EndIf} + + ; If destination already exists + + Push $R0 + Push $R1 + Push $R2 + push $R3 + + GetFileTime "${sourceFile}" $R0 $R1 + GetFileTime "${destinationFile}" $R2 $R3 + + IntCmp $R0 $R2 0 older_${MOVEFILE_JUMP} newer_${MOVEFILE_JUMP} + IntCmp $R1 $R3 older_${MOVEFILE_JUMP} older_${MOVEFILE_JUMP} newer_${MOVEFILE_JUMP} + + older_${MOVEFILE_JUMP}: + delete "${sourceFile}" + goto time_check_done_${MOVEFILE_JUMP} + + newer_${MOVEFILE_JUMP}: + delete "${destinationFile}" + rename "${sourceFile}" "${destinationFile}" + delete "${sourceFile}" ;incase above failed! + + time_check_done_${MOVEFILE_JUMP}: + + Pop $R3 + Pop $R2 + Pop $R1 + Pop $R0 + + done_${MOVEFILE_JUMP}: + + !undef MOVEFILE_JUMP + + !macroend + +;================== +; MoveFolder macro +;================== + + !macro MoveFolder source destination mask + + !define MOVEFOLDER_JUMP ${__LINE__} + + Push $R0 + Push $R1 + + ; Move path parameters into registers so they can be altered if necessary + + StrCpy $R0 "${source}" + StrCpy $R1 "${destination}" + + ; Sort out paths - remove final backslash if supplied + + Push $0 + + ; Source + StrCpy $0 "$R0" 1 -1 + StrCmp $0 '\' 0 +2 + StrCpy $R0 "$R0" -1 + + ; Destination + StrCpy $0 "$R1" 1 -1 + StrCmp $0 '\' 0 +2 + StrCpy $R1 "$R1" -1 + + Pop $0 + + ; Create destination dir + + CreateDirectory "$R1\" + + ; Add message to details-view/install-log + + DetailPrint "Moving files: $R0\${mask} to $R1\" + + ; Push registers used by ${Locate} onto stack + + Push $R6 + Push $R7 + Push $R8 + Push $R9 + + ; Duplicate dir structure (to preserve empty folders and such) + + ${Locate} "$R0" "/L=D" ".MoveFolder_Locate_createDir" + + ; Locate files and move (via callback function) + + ${Locate} "$R0" "/L=F /M=${mask} /S= /G=1" ".MoveFolder_Locate_moveFile" + + ; Delete subfolders left over after move + + Push $R2 + deldir_loop_${MOVEFOLDER_JUMP}: + StrCpy $R2 0 + ${Locate} "$R0" "/L=DE" ".MoveFolder_Locate_deleteDir" + StrCmp $R2 0 0 deldir_loop_${MOVEFOLDER_JUMP} + Pop $R2 + + ; Delete empty subfolders moved - say the user just wanted to move *.apm files, they now also have a load of empty dir's from dir structure duplication! + + Push $R2 + delnewdir_loop_${MOVEFOLDER_JUMP}: + StrCpy $R2 0 + ${Locate} "$R1" "/L=DE" ".MoveFolder_Locate_deleteDir" + StrCmp $R2 0 0 delnewdir_loop_${MOVEFOLDER_JUMP} + Pop $R2 + + ; Pop registers used by ${Locate} off the stack again + + Pop $R9 + Pop $R8 + Pop $R7 + Pop $R6 + + ; Delete source folder if empty + + rmdir "$R0" + + Pop $R1 + Pop $R0 + + !undef MOVEFOLDER_JUMP + + !macroend + +;================== +; MoveFolder macro's ${Locate} callback functions +;================== + + Function .MoveFolder_Locate_createDir + + ${If} $R6 == "" + Push $R2 + StrLen $R2 "$R0" + StrCpy $R2 $R9 '' $R2 + CreateDirectory "$R1$R2" + Pop $R2 + ${EndIf} + + Push $R1 + + FunctionEnd + + Function .MoveFolder_Locate_moveFile + + Push $R2 + + ; Get path to file + + StrLen $R2 "$R0" + StrCpy $R2 $R9 '' $R2 + StrCpy $R2 "$R1$R2" + + ; If destination does not already exists simply move file + + IfFileExists "$R2" +3 0 + rename "$R9" "$R2" + goto done + + ; If overwriting without 'ifnewer' check + + ${If} $switch_overwrite == 1 + delete "$R2" + rename "$R9" "$R2" + delete "$R9" + goto done + ${EndIf} + + ; If destination already exists + + Push $0 + Push $1 + Push $2 + push $3 + + GetFileTime "$R9" $0 $1 + GetFileTime "$R2" $2 $3 + + IntCmp $0 $2 0 older newer + IntCmp $1 $3 older older newer + + older: + delete "$R9" + goto time_check_done + + newer: + delete "$R2" + rename "$R9" "$R2" + delete "$R9" ;incase above failed! + + time_check_done: + + Pop $3 + Pop $2 + Pop $1 + Pop $0 + + done: + + Pop $R2 + + Push $R1 + + FunctionEnd + + Function .MoveFolder_Locate_deleteDir + + ${If} $R6 == "" + RMDir $R9 + IntOp $R2 $R2 + 1 + ${EndIf} + + Push $R1 + + FunctionEnd diff --git a/scripts/SimpleFC.dll b/scripts/SimpleFC.dll new file mode 100755 index 0000000..73b7d96 Binary files /dev/null and b/scripts/SimpleFC.dll differ diff --git a/scripts/ZipDLL.dll b/scripts/ZipDLL.dll new file mode 100755 index 0000000..5925d59 Binary files /dev/null and b/scripts/ZipDLL.dll differ diff --git a/scripts/locate.dll b/scripts/locate.dll new file mode 100755 index 0000000..6a15df8 Binary files /dev/null and b/scripts/locate.dll differ diff --git a/scripts/windows-installer.nsi b/scripts/windows-installer.nsi new file mode 100644 index 0000000..d1b0fcf --- /dev/null +++ b/scripts/windows-installer.nsi @@ -0,0 +1,269 @@ +# Add current directory to plugin path +!addplugindir .\ + +# Architecture detection +!include x64.nsh + +# Include LogicLib (http://nsis.sourceforge.net/LogicLib) +!include 'LogicLib.nsh' + +# Include ZipDLL plugin (http://nsis.sourceforge.net/ZipDLL_plug-in) +!include 'ZipDLL.nsh' + +# Include Locate plugin (http://nsis.sourceforge.net/Locate_plugin) +!include 'locate.nsh' + +# Include MoveFileFolder plugin (http://nsis.sourceforge.net/MoveFileFolder) +!include 'FileFunc.nsh' +!insertmacro Locate +Var /GLOBAL switch_overwrite +!include 'MoveFileFolder.nsh' + +# Enable CRC +CRCCheck on + +# Require admin privledges when UAC is on +RequestExecutionLevel admin + +!searchreplace APPNAMENOHYPEN ${APPNAME} "-" " " +!define GROUPNAME "Ethereum" +!define HELPURL "https://github.com/ethercore/desktop-wallet/releases/issues" +!define UPDATEURL "https://github.com/ethercore/desktop-wallet/releases" +!define ABOUTURL "https://ethercore.org" +!define /date NOW "%Y%m%d" + +## These must be integers and can be set on the command line by NSIS with "/DMAJORVERSION=0 /DMINORVERSION=8 /DBUILDVERSION=7" +#!define VERSIONMAJOR 0 +#!define VERSIONMINOR 8 +#!define VERSIONBUILD 7 + +# Define some script globals +Name "${GROUPNAME} ${APPNAME}" +Icon "..\dist_${TYPE}\build\icon.ico" +OutFile "..\dist_${TYPE}\release\${APPNAME}-installer-${VERSIONMAJOR}-${VERSIONMINOR}-${VERSIONBUILD}.exe" +var FILEDIR +var DATADIR +var NODEDATADIR +var ARCHDIR +var SHORTCUTDIR +var DESKTOPDIR + +# Check for administrative rights +!macro VerifyUserIsAdmin +UserInfo::GetAccountType +pop $0 +${If} $0 != "admin" + messageBox mb_iconstop "Administrator rights required!" + setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED + quit +${EndIf} +!macroend + +# Create a shared function function for setting environment variables +!macro ENVFUNC un + Function ${un}setenv + + SetShellVarContext current + StrCpy $DATADIR "$APPDATA\${APPNAME}" + StrCpy $NODEDATADIR "$APPDATA\EtherCore" + StrCpy $SHORTCUTDIR "$SMPROGRAMS\${APPNAMENOHYPEN}" + StrCpy $DESKTOPDIR "$DESKTOP" + + ${If} ${RunningX64} + StrCpy $FILEDIR "$PROGRAMFILES64\${APPNAME}" + StrCpy $ARCHDIR "win-unpacked" + ${Else} + StrCpy $FILEDIR "$PROGRAMFILES32\${APPNAME}" + StrCpy $ARCHDIR "win-ia32-unpacked" + ${Endif} + + SetShellVarContext all + + FunctionEnd +!macroend + +!insertmacro ENVFUNC "" +!insertmacro ENVFUNC "un." + +function .onInit + !insertmacro VerifyUserIsAdmin + call setenv +functionEnd + +# The license page. Can use .txt or .rtf data +PageEx license + LicenseData ..\LICENSE +PageExEnd + +# Components is a good place to allow the user to select optional software to install +# For example, it could be used to allow the user to select which node they want installed and then download it +#Page components + +# Select the location to install the main program files +PageEx directory + DirVar $FILEDIR +PageExEnd + +## Select the location for Mist's data directory +#PageEx directory +# DirText "Select a location for Mist's data files (watched contracts, etc.)" +# DirVar $DATADIR +#PageExEnd + +# Select the location for the node's data directory +PageEx directory + DirText "Select a location where blockchain data will be stored" + DirVar $NODEDATADIR +PageExEnd + +# Installation +Page instfiles + +# Uninstaller confirmation page. Useful to remind the user what data (if any) will remain, for example chaindata or keystore +UninstPage uninstConfirm + +# Uninstallation section +UninstPage instfiles + +# Show details by default +ShowInstDetails show +ShowUninstDetails show + +# Mist installer instructions +Section Mist MIST_IDX + StrCpy $switch_overwrite 1 + + # set the installation directory as the destination for the following actions + SetOutPath $TEMP + # include both architecture zip files + file "..\dist_${TYPE}\release\${APPNAME}-win64-${VERSIONMAJOR}-${VERSIONMINOR}-${VERSIONBUILD}.zip" + file "..\dist_${TYPE}\release\${APPNAME}-win32-${VERSIONMAJOR}-${VERSIONMINOR}-${VERSIONBUILD}.zip" + file "..\dist_${TYPE}\build\icon.ico" + + # Extract the zip file from TEMP to the user's selected installation directory + ${If} ${RunningX64} + ZipDLL::extractALL "$TEMP\${APPNAME}-win64-${VERSIONMAJOR}-${VERSIONMINOR}-${VERSIONBUILD}.zip" "$FILEDIR" + StrCpy $ARCHDIR "win-unpacked" + ${Else} + ZipDLL::extractALL "$TEMP\${APPNAME}-win32-${VERSIONMAJOR}-${VERSIONMINOR}-${VERSIONBUILD}.zip" "$FILEDIR" + StrCpy $ARCHDIR "win-ia32-unpacked" + ${Endif} + + # Move files out of subfolder + !insertmacro MoveFolder "$FILEDIR\$ARCHDIR" "$FILEDIR" "*.*" + # Copy icon from installer (not included in zip) + !insertmacro MoveFile "$TEMP\icon.ico" "$FILEDIR\logo.ico" + + # create the uninstaller + WriteUninstaller "$FILEDIR\uninstall.exe" + + # create shortcuts with flags in the start menu programs directory + createDirectory "$SHORTCUTDIR" + createShortCut "$SHORTCUTDIR\${APPNAMENOHYPEN}.lnk" "$FILEDIR\${APPNAMENOHYPEN}.exe" '--node-datadir="$NODEDATADIR"' "$FILEDIR\${APPNAMENOHYPEN}.exe" 0 + + # create desktop shortcut + createShortCut "$DESKTOPDIR\${APPNAMENOHYPEN}.lnk" "$FILEDIR\${APPNAMENOHYPEN}.exe" '--node-datadir="$NODEDATADIR"' "$FILEDIR\${APPNAMENOHYPEN}.exe" 0 + + # create a shortcut for the program uninstaller + CreateShortCut "$SHORTCUTDIR\Uninstall.lnk" "$FILEDIR\uninstall.exe" + + ## Firewall - add rules + #SimpleFC::AdvAddRule "Geth incoming peers (TCP:30303)" "" 6 1 1 2147483647 1 "$DATADIR\binaries\Geth\unpacked\geth.exe" "" "" "EtherCore" 30303 "" "" "" + #SimpleFC::AdvAddRule "Geth outgoing peers (TCP:30303)" "" 6 2 1 2147483647 1 "$DATADIR\binaries\Geth\unpacked\geth.exe" "" "" "EtherCore" "" 30303 "" "" + #SimpleFC::AdvAddRule "Geth UDP discovery (UDP:30303)" "" 17 2 1 2147483647 1 "$DATADIR\binaries\Geth\unpacked\geth.exe" "" "" "EtherCore" "" 30303 "" "" + + # write registry strings for uninstallation + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayName" "${GROUPNAME} ${APPNAME}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "UninstallString" '"$FILEDIR\uninstall.exe"' + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "InstallLocation" '"$FILEDIR"' + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "InstallDate" "${NOW}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayIcon" '"$FILEDIR\logo.ico"' + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "Publisher" "${GROUPNAME}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "HelpLink" '"${HELPURL}"' + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "URLUpdateInfo" '"${UPDATEURL}"' + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "URLInfoAbout" '"${ABOUTURL}"' + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "VersionMajor" ${VERSIONMAJOR} + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "VersionMinor" ${VERSIONMINOR} + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "NoModify" 1 + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "NoRepair" 1 + # calculate and store installation size + Call GetInstalledSize + Pop $0 + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "EstimatedSize" "$0" + + # write registry strings for current user options + WriteRegStr HKCU "Software\${GROUPNAME} ${APPNAME}" "DATADIR" "$DATADIR" + WriteRegStr HKCU "Software\${GROUPNAME} ${APPNAME}" "NODEDATADIR" "$NODEDATADIR" + WriteRegStr HKCU "Software\${GROUPNAME} ${APPNAME}" "DESKTOPDIR" "$DESKTOPDIR" + + # Clean up temporary files + Delete "$TEMP\${APPNAME}-win32-${VERSIONMAJOR}-${VERSIONMINOR}-${VERSIONBUILD}.zip" + Delete "$TEMP\${APPNAME}-win64-${VERSIONMAJOR}-${VERSIONMINOR}-${VERSIONBUILD}.zip" +SectionEnd + +Function .onInstSuccess + ExecShell "open" "$SHORTCUTDIR" +FunctionEnd + +function un.onInit + call un.setenv + !insertmacro VerifyUserIsAdmin +functionEnd + +# uninstaller section start +Section "uninstall" + # get user settings from registry + ClearErrors + ReadRegStr $0 HKCU "Software\${GROUPNAME} ${APPNAME}" 'DATADIR' + ReadRegStr $1 HKCU "Software\${GROUPNAME} ${APPNAME}" 'NODEDATADIR' + ReadRegStr $2 HKCU "Software\${GROUPNAME} ${APPNAME}" 'DESKTOPDIR' + + IfErrors 0 +2 + MessageBox MB_ICONEXCLAMATION|MB_OK "Unable to read from the registry. Not all shortcuts will be removed" + + StrCpy $DATADIR $0 + StrCpy $NODEDATADIR $1 + StrCpy $DESKTOPDIR $2 + + # remove the link from the start menu + rmDir /r "$SHORTCUTDIR" + + # remove desktop shortcut + Delete "$DESKTOPDIR\${APPNAME}.lnk" + + # remove files from installation directory + rmDir /r /REBOOTOK "$FILEDIR" + + ## Firewall - remove rules (if exists) + #SimpleFC::AdvRemoveRule "Geth incoming peers (TCP:30303)" + #SimpleFC::AdvRemoveRule "Geth outgoing peers (TCP:30303)" + #SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)" + + # delete registry strings + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" + DeleteRegKey HKCU "Software\${GROUPNAME} ${APPNAME}" +SectionEnd + +Function un.onUnInstSuccess + MessageBox MB_OK "Opening leftover data directories (backup before deleting!)" + ExecShell "open" "$DATADIR" + ExecShell "open" "$NODEDATADIR" +FunctionEnd + + +# Return on top of stack the total size (as DWORD) of the selected/installed sections. +Var GetInstalledSize.total +Function GetInstalledSize + StrCpy $GetInstalledSize.total 0 + + ${if} ${SectionIsSelected} ${MIST_IDX} + ${locate::GetSize} "$FILEDIR" "/S=Kb" $0 $1 $2 + # TODO check for return of -1 for error + IntOp $GetInstalledSize.total $GetInstalledSize.total + $0 + ${endif} + + IntFmt $GetInstalledSize.total "0x%08X" $GetInstalledSize.total + Push $GetInstalledSize.total +FunctionEnd diff --git a/scripts/zipdll.nsh b/scripts/zipdll.nsh new file mode 100755 index 0000000..f35cdbd --- /dev/null +++ b/scripts/zipdll.nsh @@ -0,0 +1,419 @@ +;ZipDLL include file for NSIS +;Written by Tim Kosse (mailto:tim.kosse@gmx.de) +;some improvements by deguix + +;Supported languages with their translators in alphabetical order: + +;Arabic translation by asdfuae +;Brazilian Portuguese translation by "deguix" +;Chinese, Simplified translation by Kii Ali +;Chinese, Traditional traslation by "matini" and Kii Ali +;Croatian translation by "iostriz" +;Danish translation by Claus Futtrup +;French translation by "veekee" +;German translation by Tim Kosse +;Hungarian translation by Toth Laszlo +;Korean translation by Seongab Kim +;Lithuanian translation by Vytautas Krivickas +;Polish translation by Krzysztof Galuszka +;Russion translation by Sergey +;Spanish translation by "dark_boy" + +!ifndef ZIPDLL_USED + +!define ZIPDLL_USED + +!macro ZIPDLL_EXTRACT SOURCE DESTINATION FILE + + !define "FILE_${FILE}" + + !ifndef FILE_ + Push "${FILE}" + !endif + + IfFileExists "${DESTINATION}" +2 + CreateDirectory "${DESTINATION}" + + Push "${DESTINATION}" + + IfFileExists "${SOURCE}" +2 + SetErrors + + Push "${SOURCE}" + + ;The strings that will be translated are (ready to copy, + ;remove leading semicolons in your language block): + + !ifdef LANG_ENGLISH + + ;English is default language of ZipDLL, no need to push the untranslated strings + + ;StrCmp $LANGUAGE ${LANG_ENGLISH} 0 +1 + + ;Push " Error: %s" + ;Push "Could not get file attributes." + ;Push "Error: Could not get file attributes." + ;Push "Could not extract %s" + ;Push " Error: Could not extract %s" + + ;!ifdef FILE_ + ;Push " Extract: %s" + ;Push " Extracting %d files and directories" + ;Push "Extracting contents of %s to %s" + ;!else + ;Push "Specified file does not exist in archive." + ;Push "Error: Specified file does not exist in archive." + ;Push "Extracting the file %s from %s to %s" + ;!endif + + ;Push "/TRANSLATE" + + !endif + + !ifdef LANG_HUNGARIAN + + StrCmp $LANGUAGE ${LANG_HUNGARIAN} 0 +10 + + Push " Hiba: %s" + Push "Nem olvasható a fájl attribútumai." + Push "Hiba: Nem olvasható a fájl attribútumai." + Push "Nem sikerült kicsomagolni a(z) %s" + Push " Hiba: Nem sikerült kicsomagolni a(z) %s" + + !ifdef FILE_ + Push " Kicsomagolás: %s" + Push " %d fájl és mappa kicsomagolása" + Push "%s tartalom kicsomagolása a %s helyre" + !else + Push "A megadott fájl nem található az arhívumban." + Push "Hiba: A megadott fájl nem található az arhívumban." + Push "%s fájl kcsomagolása a(z) %s fájlból a %s helyre" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_FRENCH + + StrCmp $LANGUAGE ${LANG_FRENCH} 0 +10 + + Push " Erreur : %s" + Push "Impossible de récupérer les informations sur le fichier." + Push "Erreur : Impossible de récupérer les informations sur le fichier." + Push "Impossible de décompresser %s." + Push " Erreur : Impossible de décompresser %s." + + !ifdef FILE_ + Push " Décompression : %s" + Push " Décompression de %d fichiers et répertoires" + Push "Décompression des données de %s vers %s" + !else + Push "Le fichier spécifié n'existe pas dans l'archive" + Push "Erreur : Le fichier spécifié n'existe pas dans l'archive" + Push "Décompression du fichier %s depuis %s vers %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_GERMAN + + StrCmp $LANGUAGE ${LANG_GERMAN} 0 +10 + + Push " Fehler: %s" + Push "Dateiattribute konnten nicht ermittelt werden." + Push "Fehler: Dateiattribute konnten nicht ermittelt werden." + Push "%s konnte nicht dekomprimiert werden." + Push " Fehler: %s konnte nicht dekomprimiert werden." + + !ifdef FILE_ + Push " Dekomprimiere: %s" + Push " Dekomprimiere %d Dateien und Verzeichnisse" + Push "Dekomprimiere Inhalt von %s nach %s" + !else + Push "Die angegebene Datei existiert nicht im Archiv" + Push "Fehler: Die angegebene Datei existiert nicht im Archiv" + Push "Dekomprimiere Datei %s von %s nach %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_SPANISH + + StrCmp $LANGUAGE ${LANG_SPANISH} 0 +10 + + Push " Error: %s" + Push "No se obtuvieron atributos del archivo" + Push "Error: No se obtuvieron atributos del archivo" + Push "No se pudo extraer %s" + Push " Error: No se pudo extraer %s" + + !ifdef FILE_ + Push " Extraer: %s" + Push " Extrayendo %d archivos y directorios" + Push "Extraer archivos de %s a %s" + !else + Push "Archivo especificado no existe en el ZIP" + Push "Error: El archivo especificado no existe en el ZIP" + Push "Extrayendo el archivo %s de %s a %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_PORTUGUESEBR + + StrCmp $LANGUAGE ${LANG_PORTUGUESEBR} 0 +10 + + Push " Erro: %s" + Push "Não se pode ler os atributos do arquivo" + Push "Error: Não se pode ler os atributos do arquivo" + Push "Não se pode extrair %s" + Push " Erro: Não se pode extrair %s" + + !ifdef FILE_ + Push " Extraindo: %s" + Push " Extraindo %d arquivos e diretórios" + Push "Extraindo arquivos de %s a %s" + !else + Push "O arquivo especificado não existe no ZIP" + Push "Erro: O arquivo especificado não existe no ZIP" + Push "Extraindo o arquivo %s de %s a %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_TRADCHINESE + + StrCmp $LANGUAGE ${LANG_TRADCHINESE} 0 +11 + + Push " ¿ù»~: %s" + Push "µLªk¨ú±oÀÉ®×ÄÝ©Ê¡C" + Push "¿ù»~: µLªk¨ú±oÀÉ®×ÄÝ©Ê¡C" + Push "µLªk¸ÑÀ£ÁY %s" + Push " ¿ù»~¡GµLªk¸ÑÀ£ÁY %s" + + !ifdef FILE_ + Push " ¸ÑÀ£ÁY¡G%s" + Push " ¥¿¦b¸ÑÀ£ÁY %d ÀÉ®×»P¥Ø¿ý" + Push "¥¿¦b¸ÑÀ£ÁY %s ªº¤º®e¨ì %s" + !else + Push "«ü©wªºÀɮר䣦s¦b©óÀ£ÁY¥]¡C" + Push "¿ù»~¡G«ü©wªºÀɮר䣦s¦b©óÀ£ÁY¥]¡C" + Push "¥¿¦b¸ÑÀ£ÁYÀÉ®× %s ¡A±q %s ¨ì %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_SIMPCHINESE + + StrCmp $LANGUAGE ${LANG_SIMPCHINESE} 0 +11 + + Push " ´íÎó: %s" + Push "ÎÞ·¨È¡µÃÎļþÊôÐÔ¡£" + Push "´íÎó: ÎÞ·¨È¡µÃÎļþÊôÐÔ¡£" + Push "ÎÞ·¨½âѹËõ %s" + Push " ´íÎó£ºÎÞ·¨½âѹËõ %s" + + !ifdef FILE_ + Push " ½âѹËõ£º%s" + Push " ÕýÔÚ½âѹËõ %d ÎļþÓëĿ¼" + Push "ÕýÔÚ½âѹËõ %s µÄÄÚÈݵ½ %s" + !else + Push "Ö¸¶¨µÄÎļþ²¢²»´æÔÚÓÚѹËõ°ü¡£" + Push "´íÎó£ºÖ¸¶¨µÄÎļþ²¢²»´æÔÚÓÚѹËõ°ü¡£" + Push "ÕýÔÚ½âѹËõÎļþ %s £¬´Ó %s µ½ %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_LITHUANIAN + + StrCmp $LANGUAGE ${LANG_LITHUANIAN} 0 +10 + + Push " Klaida: %s" + Push "Negaleta gauti bylos nuorodu." + Push "Klaida: Negaleta gauti bylos nuorodu." + Push "Negaleta ištraukti %s" + Push " Klaida: Negaleta ištraukti %s" + + !ifdef FILE_ + Push " Ištraukiam : %s" + Push " Ištraukiame %d bylas ir katalogus" + Push "Ištraukiame viska is %s i %s" + !else + Push "Parinkta byla nesurasta šiame archyve." + Push "Klaida: Parinkta byla nesurasta šiame archyve." + Push "Ištraukiame byla %s iš %s i %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef "LANG_POLISH" + + strcmp $LANGUAGE ${LANG_POLISH} 0 +10 + + Push " B³¹d: %s" + Push "Nie mo¿e pobraæ atrybutu pliku." + Push "B³¹d: Nie mo¿e pobraæ atrybutu pliku." + Push "Nie mo¿e rozpakowaæ %s." + Push " B³¹d: Nie mo¿e rozpakowaæ %s." + + !ifdef FILE_ + Push " Rozpakuj: %s" + Push " Rozpakowywanie %d plików i katalogów" + Push "Rozpakowywanie zawartoœci %s do %s" + !else + Push "Plik nie istnieje w archiwum" + Push "B³¹d: Plik nie istnieje w archiwum" + Push "Rozpakowywanie pliku %s z %s do %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef "LANG_KOREAN" + + strcmp $LANGUAGE ${LANG_KOREAN} 0 +10 + + Push " 오류 : %s" + Push "파일 속성을 얻어올 수 없습니다." + Push "오류: 파일 속성을 얻어올 수 없습니다." + Push "%s을(를) 풀 수 없습니다." + Push " 오류: %s을(를) 풀 수 없습니다." + + !ifdef FILE_ + Push " 풀기 : %s" + Push " %d개의 파일과 폴더를 푸는 중" + Push "%s의 내용을 %s에 푸는 중" + !else + Push "지정된 파일이 압축 파일 안에 없습니다." + Push "오류: 지정된 파일이 압축 파일 안에 없습니다." + Push "%s 파일을 %s에서 %s로 푸는 중" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef "LANG_RUSSIAN" + + strcmp $LANGUAGE ${LANG_RUSSIAN} 0 +10 + + Push " Îøèáêà: %s" + Push "Íå ìîãó ïîëó÷èòü àòðèáóòû ôàéëà." + Push "Îøèáêà: Íå ìîãó ïîëó÷èòü àòðèáóòû ôàéëà." + Push "Íå ìîãó èçâëå÷ü %s" + Push " Îøèáêà: Íå ìîãó èçâëå÷ü %s" + + !ifdef LANG_ + Push " Èçâëåêàþ : %s" + Push " Èçâëå÷åíèå %d ôàéëîâ è ïàïîê" + Push "Ñïèñîê èçâëåêàåìûõ ôàéëîâ èç %s â %s" + !else + Push "Èçâëåêàåìûé ôàéë íå îáíàðóæåí â àðõèâå." + Push "Îøèáêà: SÈçâëåêàåìûé ôàéë íå îáíàðóæåí â àðõèâå." + Push "Èçâëå÷åíèå ôàéëà %s èç %s â %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_ARABIC + + StrCmp $LANGUAGE ${LANG_ARABIC} 0 +10 + + Push " ÎØÇÁ: %s" + Push "áã íÍÕá Úáì ÎÕÇÆÕ ÇáãáÝ." + Push "ÎØÇÁ: áã íÍÕá Úáì ÎÕÇÆÕ ÇáãáÝ." + Push "áÇ íãßä ÇÓÊÎÑÇÌ %s" + Push " ÎØÇÁ: áÇ íãßä ÇÓÊÎÑÇÌ %s" + + !ifdef FILE_ + Push " ÇÓÊÎÑÇÌ : %s" + Push " ÇÓÊÎÑÇÌ ãÌáÏÇÊ æ ãáÝÇÊ %d" + Push "ÇÓÊÎÑÇÌ ãÍÊæíÇÊ %s Åáì %s" + !else + Push "ÇáãáÝ ÛíÑ ãæÌæÏ Ýí ÇáÓÌá." + Push "ÎØÇÁ: ÇáãáÝ ÛíÑ ãæÌæÏ Ýí ÇáÓÌá." + Push "ÇÓÊÎÑÇÌ ÇáãáÝ %s ãä %s Åáì %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_DANISH + + StrCmp $LANGUAGE ${LANG_DANISH} 0 +10 + + Push " Fejl: %s" + Push "Kunne ikke læse fil attributter." + Push "Fejl: Kunne ikke læse fil attributter." + Push "Kunne ikke udpakke %s" + Push " Fejl: Kunne ikke udpakke %s" + + !ifdef FILE_ + Push " Udpakker: %s" + Push " Udpakker %d filer og mapper" + Push "Udpakker indhold fra %s til %s" + !else + Push "Specificeret fil eksisterer ikke i filarkivet" + Push "Fejl: Specificeret fil eksisterer ikke i filarkivet" + Push "Udpakker fil %s fra %s til %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef LANG_CROATIAN + + StrCmp $LANGUAGE ${LANG_CROATIAN} 0 +10 + + Push " Greška: %s" + Push "Ne mogu dohvatiti atribute datoteke." + Push "Greška: Ne mogu dohvatiti atribute datoteke." + Push "Ne mogu ekstrahirati %s" + Push " Greška: Ne mogu ekstrahirati %s" + + !ifdef FILE_ + Push " Ekstrakcija: %s" + Push " Ekstrakcija %d datoteka i mapa" + Push "Ekstrakcija sadržaja %s u %s" + !else + Push "Tražena datoteka ne postoji u arhivi." + Push "Greška: Tražena datoteka ne postoji u arhivi." + Push "Ekstrakcija datoteke %s iz %s u %s" + !endif + + Push "/TRANSLATE" + + !endif + + !ifdef FILE_ + ZipDLL::extractall + !else + ZipDLL::extractfile + !endif + + !undef "FILE_${FILE}" + +!macroend + +!endif diff --git a/sounds/bip.mp3 b/sounds/bip.mp3 new file mode 100644 index 0000000..2c7e790 Binary files /dev/null and b/sounds/bip.mp3 differ diff --git a/sounds/bloop.mp3 b/sounds/bloop.mp3 new file mode 100644 index 0000000..6e3466c Binary files /dev/null and b/sounds/bloop.mp3 differ diff --git a/sounds/invite.mp3 b/sounds/invite.mp3 new file mode 100644 index 0000000..be60274 Binary files /dev/null and b/sounds/invite.mp3 differ diff --git a/tests/.eslintrc.yml b/tests/.eslintrc.yml new file mode 100644 index 0000000..0be095d --- /dev/null +++ b/tests/.eslintrc.yml @@ -0,0 +1,9 @@ +globals: # don't warn about missing declarations + describe: true + it: true + expect: true + chai: true + $: true + LastVisitedPages: true + History: true + localStorage: true diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..13a868f --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,4 @@ +mist.log +webdriver/ +chrome.log + diff --git a/tests/_base.js b/tests/_base.js new file mode 100644 index 0000000..38d531c --- /dev/null +++ b/tests/_base.js @@ -0,0 +1,489 @@ +require('co-mocha'); +const _ = require('underscore'); +const genomatic = require('genomatic'); +const Q = require('bluebird'); +const fs = require('fs'); +const Web3 = require('web3'); +const shell = require('shelljs'); +const path = require('path'); +const gethPrivate = require('geth-private'); +const Application = require('spectron').Application; +const chai = require('chai'); +const http = require('http'); +const ecstatic = require('ecstatic'); +const express = require('express'); +const ClientBinaryManager = require('ethereum-client-binaries').Manager; +const logger = require('../modules/utils/logger'); + +chai.should(); + +process.env.TEST_MODE = 'true'; + +const log = logger.create('base'); + +const startGeth = function*() { + let gethPath; + + const config = JSON.parse( + fs.readFileSync(path.join('clientBinaries.json')).toString() + ); + const manager = new ClientBinaryManager(config); + yield manager.init(); + + if (!manager.clients.Geth.state.available) { + gethPath = manager.clients.Geth.activeCli.fullPath; + console.info('Downloading geth...'); + const downloadedGeth = yield manager.download('Geth'); + gethPath = downloadedGeth.client.activeCli.fullPath; + console.info('Geth downloaded at:', gethPath); + } + + const geth = gethPrivate({ + gethPath, + balance: 5, + genesisBlock: { + config: { + chainId: 33333 + }, + difficulty: '0x01', + extraData: '0x01' + }, + gethOptions: { + port: 58546, + rpcport: 58545 + } + }); + + console.info('Geth starting...'); + yield geth.start(); + console.info('Geth started'); + + return geth; +}; + +const startFixtureServer = function(serverPort) { + log.info('Starting fixture server...'); + const app = express(); + app.use(express.static(path.join(__dirname, 'fixtures'))); + + app.get('/redirect', (req, res) => { + // Redirects to param ?url=XX + res.redirect(302, req.query.to); + }); + app.listen(serverPort); + log.info('Fixture server started'); + return app; +}; + +exports.mocha = (_module, options) => { + const tests = {}; + + options = _.extend( + { + app: 'mist' + }, + options + ); + + _module.exports[options.name || path.basename(_module.filename)] = { + *before() { + this.timeout(1e7); + + this.assert = chai.assert; + this.expect = chai.expect; + + const mistLogFile = path.join(__dirname, 'mist.log'); + const chromeLogFile = path.join(__dirname, 'chrome.log'); + const webdriverLogDir = path.join(__dirname, 'webdriver'); + + _.each([mistLogFile, webdriverLogDir, chromeLogFile], e => { + console.info('Removing log files', e); + shell.rm('-rf', e); + }); + + this.geth = yield startGeth(); + + const appFileName = options.app === 'wallet' ? 'EtherCore Wallet' : 'Mist'; + const platformArch = `${process.platform}-${process.arch}`; + console.info(`${appFileName} :: ${platformArch}`); + + let appPath; + const ipcProviderPath = path.join(this.geth.dataDir, 'geth.ipc'); + + switch (platformArch) { + case 'darwin-x64': + appPath = path.join( + process.cwd(), + `dist_${options.app}`, + 'dist', + 'mac', + `${appFileName}.app`, + 'Contents', + 'MacOS', + appFileName + ); + break; + case 'linux-x64': + appPath = path.join( + process.cwd(), + `dist_${options.app}`, + 'dist', + 'linux-unpacked', + appFileName.toLowerCase() + ); + break; + default: + throw new Error( + `Cannot run tests on ${platformArch}, please run on: darwin-x64, linux-x64` + ); + } + console.info(`appPath: ${appPath}`); + + // check that appPath exists + if (!shell.test('-f', appPath)) { + throw new Error(`Cannot find binary: ${appPath}`); + } + + this.web3 = new Web3( + new Web3.providers.HttpProvider('http://localhost:58545') + ); + this.app = new Application({ + requireName: 'electronRequire', + startTimeout: 10000, + waitTimeout: 10000, + quitTimeout: 10000, + path: appPath, + args: [ + '--loglevel', + 'debug', + '--logfile', + mistLogFile, + '--node-datadir', + this.geth.dataDir, + '--rpc', + ipcProviderPath + ], + webdriverLogPath: webdriverLogDir, + chromeDriverLogPath: chromeLogFile + }); + + console.info('Starting app...'); + yield this.app.start(); + console.info('App started'); + + this.client = this.app.client; + + /* + Starting HTTP server for HTML fixtures + */ + const serverPort = 8080; + this.httpServer = startFixtureServer(serverPort); + this.fixtureBaseUrl = `http://localhost:${serverPort}/`; + + /* + Utility methods + */ + for (const key in Utils) { + this[key] = genomatic.bind(Utils[key], this); + } + + // Loop over windows trying to select Main Window + const app = this; + const selectMainWindow = function*(mainWindowSearch, retries = 20) { + console.log(`selectMainWindow retries remaining: ${retries}`); + let windowHandles = (yield app.client.windowHandles()).value; + + for (let handle in windowHandles) { + yield app.client.window(windowHandles[handle]); + const windowUrl = yield app.client.getUrl(); + const isMainWindow = mainWindowSearch.test(windowUrl); + if (isMainWindow) return true; + } + + if (retries === 0) throw new Error('Failed to select main window'); + + // not main window. try again after 2 seconds. + yield Q.delay(2000); + yield selectMainWindow(mainWindowSearch, --retries); + }; + + const mainWindowSearch = + options.app === 'wallet' ? /^file:\/\/\/$/ : /interface\/index\.html$/; + yield selectMainWindow(mainWindowSearch); + console.log('Main window selected'); + + this.mainWindowHandle = (yield this.client.windowHandle()).value; + }, + + *beforeEach() { + yield this.app.client.window(this.mainWindowHandle); + + yield this.client.execute(() => { + // Code executed in context of browser + Tabs.remove({}); + LastVisitedPages.remove({}); + History.remove({}); + + Tabs.insert({ + _id: 'browser', + url: 'http://localhost:8080/', + redirect: 'http://localhost:8080/', + position: 0 + }); + Tabs.upsert( + { _id: 'wallet' }, + { + $set: { + url: 'https://wallet.ethereum.org', + redirect: 'https://wallet.ethereum.org', + position: 1, + permissions: { admin: true } + } + } + ); + + LocalStore.set('selectedTab', 'browser'); + }); + yield Q.delay(1000); + }, + + // * afterEach() { }, + + *after() { + if (this.app && this.app.isRunning()) { + console.log('Stopping app...'); + yield this.app.stop(); + } + + if (this.geth && this.geth.isRunning) { + console.log('Stopping geth...'); + yield this.geth.stop(); + } + + if (this.httpServer && this.httpServer.isListening) { + console.log('Stopping http server...'); + yield this.httpServer.close(); + } + }, + + tests + }; + + return tests; +}; + +const Utils = { + *waitUntil(msg, promiseFn) { + yield this.client.waitUntil(promiseFn, 10000, msg, 500); + }, + *waitForText( + selector, + text, + ms = 5000, + message = "Element couldn't be found" + ) { + const client = this.client; + yield client.waitUntil( + () => { + return client.getText(selector).then(e => { + return e === text; + }); + }, + ms, + message + ); + }, + *getUiElements(selector) { + const elems = yield this.client.elements(selector); + + return elems.value; + }, + *getUiElement(selector) { + const elem = yield this.client.element(selector); + + return elem.value; + }, + *openAndFocusNewWindow(type, fnPromise) { + yield fnPromise(); + const handle = yield this.selectWindowHandleByType(type); + yield this.client.window(handle); + }, + *selectWindowHandleByType(type) { + const client = this.client; + const windowHandles = (yield client.windowHandles()).value; + + for (let handle in windowHandles) { + yield client.window(windowHandles[handle]); + const windowUrl = yield client.getUrl(); + if (new RegExp(type).test(windowUrl)) { + return windowHandles[handle]; + } + } + }, + *execElemsMethod(clientElementIdMethod, selector) { + const elems = yield this.client.elements(selector); + + const values = yield elems.value.map(e => + this.client[clientElementIdMethod](e.ELEMENT) + ); + + return values.map(r => r.value); + }, + *execElemMethod(clientElementIdMethod, selector) { + const e = yield this.client.element(selector); + + console.log(e); + + const value = yield this.client[clientElementIdMethod](e.ELEMENT); + + return value.value; + }, + *capturePage() { + const pageImage = yield this.app.browserWindow.capturePage(); + + if (!pageImage) { + throw new Error('Page capture failed'); + } + + fs.writeFileSync(path.join(__dirname, 'mist.png'), pageImage); + }, + *getRealAccountBalances() { + let accounts = this.web3.eth.accounts; + + let balances = accounts.map( + acc => `${this.web3.fromWei(this.web3.eth.getBalance(acc), 'ether')}` + ); + + accounts = accounts.map(a => a.toLowerCase()); + balances = balances.map(b => parseInt(b, 10)); + + return _.object(accounts, balances); + }, + *getUiAccountBalances() { + // check balances on the pgetUiAccountsBalancesage + let _accounts = yield this.execElemsMethod( + 'elementIdText', + '.wallet-box .account-id' + ); + let _balances = yield this.execElemsMethod( + 'elementIdText', + '.wallet-box .account-balance' + ); + + _accounts = _accounts.map(a => a.toLowerCase()); + _balances = _balances.map(b => parseInt(b, 10)); + + return _.object(_accounts, _balances); + }, + *openAccountInUi(accId) { + const _accounts = yield this.execElemsMethod( + 'elementIdText', + '.wallet-box .account-id' + ); + + let idx = -1; + + const accountId = accId.toLowerCase(); + + for (const i in _accounts) { + if (_accounts[i].toLowerCase() === accountId) { + idx = i; + } + } + + if (idx < 0) { + throw new Error('Unable to find account in UI'); + } + + const accLinks = yield this.client.elements('.wallet-box'); + + yield this.client.elementIdClick(accLinks.value[idx].ELEMENT); + + yield Q.delay(1000); + }, + *startMining() { + yield this.geth.consoleExec('miner.start();'); + }, + *stopMining() { + yield this.geth.consoleExec('miner.stop();'); + }, + + *selectTab(tabId) { + yield this.getUiElement(`.sidebar [data-tab-id=${tabId}]`); + yield this.client.click(`.sidebar [data-tab-id=${tabId}] button.main`); + // TODO: returns webview reference + }, + + *getSelectedWebviewParam(param) { + const selectedTabId = (yield this.client.execute(() => { + return localStorage.getItem('selectedTab'); + })).value; + return yield this.client.getAttribute( + `webview[data-id=${selectedTabId}]`, + param + ); + }, + + *loadFixture(uri = '') { + const client = this.client; + yield client.setValue('#url-input', `${this.fixtureBaseUrl}${uri}`); + yield client.submitForm('form.url'); + yield client.waitUntil( + () => { + return client.getText('.dapp-info span', e => { + /Fixture/.test(e); + }); + }, + 3000, + 'expected to properly load fixture' + ); + }, + + *getBrowserBarText() { + return yield this.client.getText('.url-breadcrumb'); + }, + + *pinCurrentTab() { + const client = this.client; + yield this.openAndFocusNewWindow('connectAccount', () => { + return client.click('span.connect-button'); + }); + yield client.click('.dapp-primary-button'); + yield this.delay(500); + yield client.window(this.mainWindowHandle); // selects main window again + + const pinnedWebview = (yield client.windowHandles()).value.pop(); + return pinnedWebview; + }, + + *delay(ms) { + yield this.waitUntil('delay', async () => { + return new Promise(resolve => setTimeout(() => resolve(true), ms)); + }); + }, + + *navigateTo(url) { + const client = this.client; + yield client.setValue('#url-input', url); + yield client.submitForm('form.url'); + }, + + /* + @method getWindowByUrl + + @param search: function that tells how to search by window + @param tries: amount of tries left until give up searching for + */ + *getWindowByUrl(search, tries = 5) { + if (tries < 0) + throw new Error("Couldn't select window using given parameters."); + const windowHandles = (yield this.client.windowHandles()).value; + for (let handle in windowHandles) { + yield this.client.window(windowHandles[handle]); + const found = !!search(yield this.client.getUrl()); + if (found) return true; + } + yield Q.delay(500); + yield this.getWindowByUrl(search, --tries); //eslint-disable-line + } +}; diff --git a/tests/fixtures/fixture-popup.html b/tests/fixtures/fixture-popup.html new file mode 100644 index 0000000..97aa033 --- /dev/null +++ b/tests/fixtures/fixture-popup.html @@ -0,0 +1,10 @@ + + + Fixture Popup + + +

Fixture Popup

+ Target blank + Target popup + + diff --git a/tests/fixtures/index.html b/tests/fixtures/index.html new file mode 100644 index 0000000..6a1364a --- /dev/null +++ b/tests/fixtures/index.html @@ -0,0 +1,11 @@ + + + Fixture title + + +

Index page

+

This is a fixture page

+ + + diff --git a/tests/fixtures/js-redirect.html b/tests/fixtures/js-redirect.html new file mode 100644 index 0000000..3a0c9f5 --- /dev/null +++ b/tests/fixtures/js-redirect.html @@ -0,0 +1,17 @@ + + + JS redirect fixture + + +

JS redirect fixture

+ + + + diff --git a/tests/fixtures/meta-redirect.html b/tests/fixtures/meta-redirect.html new file mode 100644 index 0000000..bd0f7a3 --- /dev/null +++ b/tests/fixtures/meta-redirect.html @@ -0,0 +1,9 @@ + + + Meta redirect fixture + + + +

Meta redirect fixture

+ + diff --git a/tests/fixtures/page-01.html b/tests/fixtures/page-01.html new file mode 100644 index 0000000..4779eba --- /dev/null +++ b/tests/fixtures/page-01.html @@ -0,0 +1,8 @@ + + + Fixture 01 + + +

Fixture 01

+ + diff --git a/tests/mist/basic.test.js b/tests/mist/basic.test.js new file mode 100644 index 0000000..de50543 --- /dev/null +++ b/tests/mist/basic.test.js @@ -0,0 +1,331 @@ +const Q = require('bluebird'); +const path = require('path'); +const should = require('chai').should(); + +const test = require('../_base').mocha(module, { + app: 'mist' +}); + +test['Check for Mist title'] = function*() { + (yield this.client.getTitle()).should.eql('Mist'); +}; + +test['Sanity Check: main window is focused'] = function*() { + const client = this.client; + (yield client.getUrl()).should.match(/interface\/index\.html$/); +}; + +test['Browser bar should render urls with separators'] = function*() { + yield this.navigateTo('http://localhost:8080/page1/page2?param=value#hash'); + yield Q.delay(500); + yield this.waitForText( + '.url-breadcrumb', + 'http://localhost:8080 ▸ page1 ▸ page2 ▸ param=value ▸ hash' + ); +}; + +test[ + 'Browser bar should not render script tags on breadcrumb view' +] = function*() { + // ETH-01-001 + yield this.navigateTo(''); + yield Q.delay(1500); + + const webviewErrorURL = yield this.getSelectedWebviewParam('src'); + webviewErrorURL.should.match(/errorPages\/404\.html$/); + + should.exist(yield this.getUiElement('form.url')); + should.not.exist(yield this.getUiElement('form.url script')); +}; + +test[ + 'Browser bar should not render script tags in disguise on breadcrumb view' +] = function*() { + // ETH-01-001 + const client = this.client; + + yield client.setValue('#url-input', '<script>alert()</script>'); + const isUrlBlocked = (yield client.execute(() => { + // Code executed in context of browser + try { + $('form.url').submit(); + } catch (e) { + return /Invalid URL/.test(e); + } + return false; + })).value; + + isUrlBlocked.should.be.true; + should.not.exist(yield this.getUiElement('form.url script')); +}; + +test[ + 'Browser bar should not render script tags in disguise (2) on breadcrumb view' +] = function*() { + // ETH-01-001 + yield this.navigateTo(''); + yield Q.delay(1500); + + should.exist(yield this.getUiElement('form.url')); + should.not.exist(yield this.getUiElement('form.url svg')); + should.not.exist(yield this.getUiElement('form.url script')); + + const webviewErrorURL = yield this.getSelectedWebviewParam('src'); + webviewErrorURL.should.match(/errorPages\/404\.html$/); +}; + +test['Browser bar should not render arbitrary code as HTML'] = function*() { + // ETH-01-001 + const client = this.client; + + yield client.waitUntil( + () => { + return client.getText('.url-breadcrumb', e => { + return e === '%3Ciframe onload="alert%28%29%"%3E'; + }); + }, + 5000, + 'expected breadcrumb to render as HTML encoded' + ); +}; + +test['Browser bar should not execute JS'] = function*() { + // ETH-01-001 + const client = this.client; + + yield this.navigateTo(''); + const mist = yield client.execute(() => { + return window.mist; + }); // checking if `execute` works + const pwned = yield client.execute(() => { + return window.pwned; + }); + + should.exist(mist.value); + should.not.exist(pwned.value); +}; + +test['Should select Wallet and Browse tabs properly'] = function*() { + yield this.selectTab('wallet'); +}; + +test['Load fixture page'] = function*() { + yield this.loadFixture(); +}; + +test['"http" protocol should be allowed on browser bar'] = function*() { + // ETH-01-002 + const client = this.client; + yield this.loadFixture(); + + yield client.setValue('#url-input', `${this.fixtureBaseUrl}index.html`); + const isProtocolBlocked = (yield client.execute(() => { + // Code executed in context of browser + try { + $('form.url').submit(); + } catch (e) { + return /Invalid URL/.test(e); + } + return false; + })).value; + isProtocolBlocked.should.be.false; + + yield this.waitForText( + '.url-breadcrumb', + 'http://localhost:8080 ▸ index.html' + ); + + const browserBarText = yield this.client.getText('.url-breadcrumb'); + browserBarText.should.eql('http://localhost:8080 ▸ index.html'); // checks that did change displayed URL +}; + +test[ + '"javascript" protocol should be disallowed on browser bar' +] = function*() { + // ETH-01-002 + const client = this.client; + yield this.loadFixture(); + yield client.setValue('#url-input', 'javascript:window.close()'); // eslint-disable-line no-script-url + + const isProtocolBlocked = (yield client.execute(() => { + // Code executed in context of browser + try { + $('form.url').submit(); + } catch (e) { + return /Invalid URL/.test(e); + } + return false; + })).value; + isProtocolBlocked.should.be.true; + + yield Q.delay(800); + const browserBarText = yield this.getBrowserBarText(); + browserBarText.should.eql('http://localhost:8080'); // checks that hasn't changed displayed URL +}; + +test['"data" protocol should be disallowed on browser bar'] = function*() { + // ETH-01-002 + const client = this.client; + yield this.loadFixture(); + yield client.setValue( + '#url-input', + 'data:text/plain;charset=utf-8;base64,dGhpcyB0ZXN0IGlzIG9uIGZpcmU=' + ); + + const isProtocolBlocked = (yield client.execute(() => { + // Code executed in context of browser + try { + $('form.url').submit(); + } catch (e) { + return /Invalid URL/.test(e); + } + return false; + })).value; + isProtocolBlocked.should.be.true; + + yield Q.delay(500); + const browserBarText = yield this.getBrowserBarText(); + browserBarText.should.eql('http://localhost:8080'); // checks that hasn't changed displayed URL +}; + +test['"file" protocol should be disallowed on browser bar'] = function*() { + // ETH-01-012 + const filePath = `file://${path.join( + __dirname, + '..', + 'fixtures', + 'index.html' + )}`; + + yield this.navigateTo(filePath); + yield Q.delay(1000); + + const webviewErrorURL = yield this.getSelectedWebviewParam('src'); + webviewErrorURL.should.match(/errorPages\/400\.html$/); +}; + +test['Pin tab test'] = function*() { + const client = this.client; + const sidebarItems = (yield client.elements('.sidebar nav > ul > li')).value; + + yield this.selectTab('browser'); + yield this.pinCurrentTab(); + + const sidebarItemsAfterAdd = (yield client.elements('.sidebar nav > ul > li')) + .value; + + sidebarItems.length.should.eql(2); + sidebarItemsAfterAdd.length.should.eql(3); +}; + +test[ + 'Browse tab should be changed to pinned tab if URLs are the same' +] = function*() { + // ETH-01-007 + const client = this.client; + yield this.selectTab('browser'); + + yield this.navigateTo('https://wallet.ethereum.org'); + yield Q.delay(1000); + const selectedTab = (yield client.execute(() => { + // code executed in browser context + return LocalStore.get('selectedTab'); + })).value; + + selectedTab.should.eql('wallet'); +}; + +test[ + "Wallet tab shouldn't have the page replaced if URLs does not match" +] = function*() { + // ETH-01-007 + const client = this.client; + yield this.selectTab('wallet'); + + yield this.navigateTo( + `${this.fixtureBaseUrl}index.html?https://wallet.ethereum.org` + ); + yield client.waitUntil(() => { + return client.execute(() => { + return LocalStore.get('selectedTab') === 'browser'; + }); + }, 2000); +}; + +test[ + "Wallet tab shouldn't have the page replaced if URLs does not match - 2" +] = function*() { + // ETH-01-007 + const client = this.client; + yield this.selectTab('wallet'); + + // Now changing address via JS + yield client.setValue( + '#url-input', + `${this.fixtureBaseUrl}index.html?https://wallet.ethereum.org` + ); + yield client.execute(() => { + // Code executed in context of browser + $('form.url').submit(); + }); + + yield client.waitUntil(() => { + return client.execute(() => { + return LocalStore.get('selectedTab') === 'browser'; + }); + }, 2000); +}; + +//test['Links with target _blank should open inside Mist'] = function* () { +// const client = this.client; +// yield this.navigateTo(`${this.fixtureBaseUrl}/fixture-popup.html`); +// yield this.getWindowByUrl(e => /fixture-popup.html$/.test(e)); +// +// yield client.click('a[target=_blank]'); +// yield client.waitUntil(() => { +// return client.getUrl((url) => { +// return /index.html$/.test(url); +// }); +// }); +//}; + +// test['Links with target _popup should open inside Mist'] = function* () { +// const client = this.client; +// yield this.navigateTo(`${this.fixtureBaseUrl}/fixture-popup.html`); +// yield this.getWindowByUrl(e => /fixture-popup.html$/.test(e)); +// +// yield client.click('a[target=_popup]'); +// yield client.waitUntil(() => { +// return client.getUrl((url) => { +// return /index.html$/.test(url); +// }); +// }); +// }; + +// ETH-01-005 +// test['Mist main webview should not redirect to arbitrary addresses'] = function* () { +// const client = this.client; +// const initialURL = yield client.getUrl(); +// +// yield client.execute(() => { // code executed in context of browser +// window.location.href = 'http://google.com'; +// }); +// +// yield Q.delay(1000); +// (yield client.getUrl()).should.eql(initialURL); +// }; +// + +// ETH-01-008 +test['Mist main webview should not redirect to local files'] = function*() { + const client = this.client; + const url = `${ + this.fixtureBaseUrl + }redirect?to=file:///Users/ev/Desktop/keystore.txt`; + + yield this.navigateTo(url); + yield Q.delay(1000); + + const webviewErrorURL = yield this.getSelectedWebviewParam('src'); + webviewErrorURL.should.match(/errorPages\/400\.html$/); +}; diff --git a/tests/mocha-in-browser/.eslintrc.yml b/tests/mocha-in-browser/.eslintrc.yml new file mode 100644 index 0000000..49145ee --- /dev/null +++ b/tests/mocha-in-browser/.eslintrc.yml @@ -0,0 +1,14 @@ +rules: + no-undef: 0 + no-var: 0 + prefer-arrow-callback: 0 + func-names: 0 + prefer-template: 0 + no-unused-expressions: 0 + no-underscore-dangle: + - error + - allow: ['_id', '_escape'] + +globals: + mist: true + expect: true diff --git a/tests/mocha-in-browser/.gitignore b/tests/mocha-in-browser/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/tests/mocha-in-browser/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/tests/mocha-in-browser/Makefile b/tests/mocha-in-browser/Makefile new file mode 100644 index 0000000..629a462 --- /dev/null +++ b/tests/mocha-in-browser/Makefile @@ -0,0 +1,10 @@ +update : + npm install + cp node_modules/mocha/mocha.js spec/lib/ + curl https://raw.github.com/visionmedia/mocha/master/mocha.css > spec/lib/browser/mocha.css + +zipit : update + rm -f mocha-in-browser.zip + rm -fr node_modules + zip -r mocha-in-browser.zip public/ spec/ + diff --git a/tests/mocha-in-browser/README.md b/tests/mocha-in-browser/README.md new file mode 100644 index 0000000..dd20379 --- /dev/null +++ b/tests/mocha-in-browser/README.md @@ -0,0 +1,12 @@ +# Mocha In the Browser + +A super simple example of how [Mocha](http://visionmedia.github.com/mocha/) tests +can be executed in the browser. A great way to start is cloning this project and +working through the [String Calculator Kata](http://osherove.com/tdd-kata-1/). +Open up the public/index.html file in a browser to see the JavaScript object +used by the page. + +### Integrating it into your project + +Copy the spec directory into your project. Make sure the runner.html file has all +the right paths. diff --git a/tests/mocha-in-browser/lib/browser/jquery-1.10.1.min.js b/tests/mocha-in-browser/lib/browser/jquery-1.10.1.min.js new file mode 100644 index 0000000..e407e76 --- /dev/null +++ b/tests/mocha-in-browser/lib/browser/jquery-1.10.1.min.js @@ -0,0 +1,6 @@ +/*! jQuery v1.10.1 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery-1.10.1.min.map +*/ +(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.1",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=lt(),k=lt(),E=lt(),S=!1,A=function(){return 0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=bt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+xt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return At(e.replace(z,"$1"),t,n,i)}function st(e){return K.test(e+"")}function lt(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function ut(e){return e[b]=!0,e}function ct(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function pt(e,t,n){e=e.split("|");var r,i=e.length,a=n?null:t;while(i--)(r=o.attrHandle[e[i]])&&r!==t||(o.attrHandle[e[i]]=a)}function ft(e,t){var n=e.getAttributeNode(t);return n&&n.specified?n.value:e[t]===!0?t.toLowerCase():null}function dt(e,t){return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}function ht(e){return"input"===e.nodeName.toLowerCase()?e.defaultValue:t}function gt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function mt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function yt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function vt(e){return ut(function(t){return t=+t,ut(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.parentWindow;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.frameElement&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ct(function(e){return e.innerHTML="",pt("type|href|height|width",dt,"#"===e.firstChild.getAttribute("href")),pt(B,ft,null==e.getAttribute("disabled")),e.className="i",!e.getAttribute("className")}),r.input=ct(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}),pt("value",ht,r.attributes&&r.input),r.getElementsByTagName=ct(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ct(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ct(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=st(n.querySelectorAll))&&(ct(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ct(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=st(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ct(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=st(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},r.sortDetached=ct(function(e){return 1&e.compareDocumentPosition(n.createElement("div"))}),A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return gt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?gt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:ut,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=bt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?ut(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ut(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?ut(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ut(function(e){return function(t){return at(e,t).length>0}}),contains:ut(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:ut(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:vt(function(){return[0]}),last:vt(function(e,t){return[t-1]}),eq:vt(function(e,t,n){return[0>n?n+t:n]}),even:vt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:vt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:vt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:vt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=mt(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=yt(n);function bt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function xt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function wt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function Tt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Ct(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function Nt(e,t,n,r,i,o){return r&&!r[b]&&(r=Nt(r)),i&&!i[b]&&(i=Nt(i,o)),ut(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||St(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:Ct(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=Ct(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=Ct(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function kt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=wt(function(e){return e===t},s,!0),p=wt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[wt(Tt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return Nt(l>1&&Tt(f),l>1&&xt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&kt(e.slice(l,r)),i>r&&kt(e=e.slice(r)),i>r&&xt(e))}f.push(n)}return Tt(f)}function Et(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=Ct(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?ut(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=bt(e)),n=t.length;while(n--)o=kt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Et(i,r))}return o};function St(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function At(e,t,n,i){var a,s,u,c,p,f=bt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&xt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}o.pseudos.nth=o.pseudos.eq;function jt(){}jt.prototype=o.filters=o.pseudos,o.setFilters=new jt,r.sortStable=b.split("").sort(A).join("")===b,p(),[0,0].sort(A),r.detectDuplicates=S,x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!l||i&&!u||(n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
t
",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null) +}),n=s=l=u=r=o=null,t}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=x(this),l=t,u=e.match(T)||[];while(o=u[a++])l=r?l:!s.hasClass(o),s[l?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); +u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("