├── contract
├── as-pect.config.js
├── asconfig.json
├── assembly
│ ├── as_types.d.ts
│ ├── __tests__
│ │ ├── as-pect.d.ts
│ │ └── main.spec.ts
│ ├── tsconfig.json
│ └── index.ts
├── package.json
└── README.md
├── out
└── .gitignore
├── .github
├── dependabot.yml
└── workflows
│ └── tests.yml
├── neardev
└── shared-test
│ └── test.near.json
├── .gitpod.Dockerfile
├── README.md
├── .travis.yml
├── ava.config.cjs
├── integration-tests
├── rs
│ ├── Cargo.toml
│ └── src
│ │ └── tests.rs
└── ts
│ └── main.ava.ts
├── .gitignore
├── LICENSE
├── .gitpod.yml
├── README-Gitpod.md
├── package.json
├── frontend
├── assets
│ ├── js
│ │ ├── near
│ │ │ ├── config.js
│ │ │ └── utils.js
│ │ └── main.js
│ └── css
│ │ └── global.css
└── index.html
└── LICENSE-APACHE
/contract/as-pect.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('near-sdk-as/imports')
2 |
--------------------------------------------------------------------------------
/contract/asconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "near-sdk-as/asconfig.json"
3 | }
4 |
--------------------------------------------------------------------------------
/contract/assembly/as_types.d.ts:
--------------------------------------------------------------------------------
1 | ///
--------------------------------------------------------------------------------
/contract/assembly/__tests__/as-pect.d.ts:
--------------------------------------------------------------------------------
1 | ///
--------------------------------------------------------------------------------
/out/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/contract/assembly/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "assemblyscript/std/assembly.json",
3 | "include": [
4 | "./**/*.ts"
5 | ]
6 | }
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 |
--------------------------------------------------------------------------------
/neardev/shared-test/test.near.json:
--------------------------------------------------------------------------------
1 | {"account_id":"test.near","private_key":"ed25519:2wyRcSwSuHtRVmkMCGjPwnzZmQLeXLzLLyED1NDMt4BjnKgQL6tF85yBx6Jr26D2dUNeC716RBoTxntVHsegogYw"}
2 |
--------------------------------------------------------------------------------
/.gitpod.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM gitpod/workspace-full
2 |
3 | RUN bash -c ". .nvm/nvm.sh \
4 | && nvm install v12 && nvm alias default v12 \
5 | && nvm use default && npm i -g yarn && alias near='yarn near'" \
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Deprecated
2 |
3 | > The NEAR community is not actively supporting Assemblyscript anymore
4 |
5 | This repository is not being acively maintained anymore, please use the [typescript version instead](https://github.com/near-examples/counter-js).
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | os:
3 | - linux
4 | - osx
5 | - windows
6 | node_js:
7 | - 12
8 | env:
9 | - NODE_ENV=ci YARN_GPG=no
10 | - NODE_ENV=ci-betanet YARN_GPG=no
11 | cache: yarn
12 | script:
13 | - yarn build
14 | - yarn test
15 |
--------------------------------------------------------------------------------
/ava.config.cjs:
--------------------------------------------------------------------------------
1 | require("util").inspect.defaultOptions.depth = 5; // Increase AVA's printing depth
2 |
3 | module.exports = {
4 | timeout: "300000",
5 | files: ["**/*.ava.ts"],
6 | failWithoutAssertions: false,
7 | extensions: ["ts"],
8 | require: ["ts-node/register"],
9 | };
10 |
--------------------------------------------------------------------------------
/contract/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "counter_contract",
3 | "version": "1.0.0",
4 | "license": "UNLICENSED",
5 | "private": true,
6 | "scripts": {
7 | "build": "asb",
8 | "test": "asp --nologo"
9 | },
10 | "dependencies": {
11 | "near-sdk-as": "^3.2.3"
12 | },
13 | "devDependencies": {}
14 | }
15 |
--------------------------------------------------------------------------------
/integration-tests/rs/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "integration-tests"
3 | version = "1.0.0"
4 | publish = false
5 | edition = "2018"
6 |
7 | [dev-dependencies]
8 | anyhow = "1.0"
9 | borsh = "0.9"
10 | maplit = "1.0"
11 | near-units = "0.2.0"
12 | # arbitrary_precision enabled for u128 types that workspaces requires for Balance types
13 | serde_json = { version = "1.0", features = ["arbitrary_precision"] }
14 | tokio = { version = "1.18.1", features = ["full"] }
15 | tracing = "0.1"
16 | tracing-subscriber = { version = "0.3.11", features = ["env-filter"] }
17 | workspaces = "0.4.0"
18 | pkg-config = "0.3.1"
19 |
20 | [[example]]
21 | name = "integration-tests"
22 | path = "src/tests.rs"
23 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 | on:
3 | repository_dispatch:
4 | types: [tests-report]
5 | push:
6 | jobs:
7 | tests:
8 | strategy:
9 | matrix:
10 | platform: [ubuntu-latest] # mac-os in development
11 | runs-on: ${{ matrix.platform }}
12 | steps:
13 | - name: Checkout branch
14 | uses: actions/checkout@v2
15 | - name: Install Node
16 | uses: actions/setup-node@v2
17 | - name: Install Rust
18 | uses: actions-rs/toolchain@v1
19 | with:
20 | toolchain: stable
21 | target: wasm32-unknown-unknown
22 | - name: Install modules
23 | run: yarn
24 | - name: Run tests
25 | run: yarn test
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ##########################################
2 | # this file is useful with create-near-app
3 | ##########################################
4 |
5 | # ignore Mac OS noise
6 | .DS_Store
7 |
8 | # ignore large, hairy, autogenerated folders
9 | node_modules/
10 | default/
11 | target/
12 |
13 | # ignore accounts generated by tests
14 | neardev/shared-test/*
15 | # but not the original test.near.json account
16 | !neardev/shared-test/test.near.json
17 |
18 | # ignore any default network private keys and dev-account
19 | neardev/default/*
20 | neardev/dev-account
21 |
22 | # ignore dev .cache
23 | .cache/
24 |
25 | # ignore dist folder generated by build process
26 | dist/
27 | out/
28 | build/
29 |
30 | # IDE files
31 | .idea
32 |
33 | # lock files
34 | *.lock
35 | *-lock.json
36 |
37 | yarn-error.log
38 |
--------------------------------------------------------------------------------
/contract/README.md:
--------------------------------------------------------------------------------
1 | new-awesome-project Smart Contract
2 | ==================
3 |
4 | A [smart contract] written in [AssemblyScript] for an app initialized with [create-near-app]
5 |
6 |
7 | Quick Start
8 | ===========
9 |
10 | Before you compile this code, you will need to install [Node.js] ≥ 12
11 |
12 |
13 | Exploring The Code
14 | ==================
15 |
16 | 1. The main smart contract code lives in `assembly/index.ts`. You can compile
17 | it with the `./compile` script.
18 | 2. Tests: You can run smart contract tests with the `./test` script. This runs
19 | standard AssemblyScript tests using [as-pect].
20 |
21 |
22 | [smart contract]: https://docs.near.org/develop/welcome
23 | [AssemblyScript]: https://www.assemblyscript.org/
24 | [create-near-app]: https://github.com/near/create-near-app
25 | [Node.js]: https://nodejs.org/en/download/package-manager/
26 | [as-pect]: https://www.npmjs.com/package/@as-pect/cli
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2020 NEAR Inc
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | image:
2 | file: .gitpod.Dockerfile
3 | # Options to prebuild the image after github events and set notifications/badges
4 | github:
5 | prebuilds:
6 | # enable for the master/default branch (defaults to true)
7 | master: true
8 | # enable for pull requests coming from this repo (defaults to true)
9 | pullRequests: true
10 | # enable for pull requests coming from forks (defaults to false)
11 | pullRequestsFromForks: true
12 | # add a check to pull requests (defaults to true)
13 | addCheck: true
14 | # add a "Review in Gitpod" button as a comment to pull requests (defaults to false)
15 | addComment: true
16 | # add a "Review in Gitpod" button to the pull request's description (defaults to false)
17 | addBadge: false
18 | # add a label once the prebuild is ready to pull requests (defaults to false)
19 | addLabel: false
20 |
21 | # List the start up tasks. You can start them in parallel in multiple terminals. See https://www.gitpod.io/docs/config-start-tasks/
22 | tasks:
23 | - before: nvm use default
24 | init: yarn
25 | command: gp open README-Gitpod.md && yarn dev
26 |
27 | ports:
28 | - port: 1234
29 | onOpen: open-browser
30 |
--------------------------------------------------------------------------------
/contract/assembly/index.ts:
--------------------------------------------------------------------------------
1 | import { storage, logging } from "near-sdk-as";
2 |
3 | // Public method - Returns the counter value
4 | export function get_num(): i8 {
5 | return storage.getPrimitive("counter", 0);
6 | }
7 |
8 | // Public method - Increment the counter
9 | export function increment(): void {
10 | safeguard_overflow()
11 | const new_value = get_num() + 1;
12 | storage.set("counter", new_value);
13 | logging.log("Increased number to " + new_value.toString());
14 | }
15 |
16 | // Public method - Decrement the counter
17 | export function decrement(): void {
18 | safeguard_underflow()
19 | const new_value = get_num() - 1;
20 | storage.set("counter", new_value);
21 | logging.log("Decreased number to " + new_value.toString());
22 | }
23 |
24 | // Public method - Reset to zero
25 | export function reset(): void {
26 | storage.set("counter", 0);
27 | logging.log("Reset counter to zero");
28 | }
29 |
30 | // Private method - Safeguard against overflow
31 | function safeguard_overflow(): void{
32 | const value = get_num()
33 | assert(value < 127, "Counter is at maximum")
34 | }
35 |
36 | // Private method - Safeguard against underflow
37 | function safeguard_underflow(): void{
38 | const value = get_num()
39 | assert(value > -128, "Counter is at minimum")
40 | }
--------------------------------------------------------------------------------
/README-Gitpod.md:
--------------------------------------------------------------------------------
1 | Counter example in AssemblyScript - Gitpod version
2 | ==================================================
3 |
4 | This README is specific to Gitpod and this example. For local development, please see [README.md](README.md).
5 |
6 | ## Description
7 |
8 | In Gitpod, the counter will start automatically. Please look in the terminal for a link to follow.
9 |
10 | This contract implements simple counter backed by storage on blockchain.
11 | Contract in `assembly/main.ts` provides methods to increment / decrement counter and get it's current value or reset.
12 |
13 | Plus and minus buttons increase and decrease value correspondingly. When button L is toggled, counter will add or minus 10 a time. RS button is for reset. LE and RE buttons to let the robot wink to you.
14 |
15 | ## To Test
16 |
17 | ```
18 | yarn asp # as-pect tests
19 | NODE_ENV=ci yarn jest # jest tests
20 | NODE_ENV=ci yarn test # both
21 | ```
22 |
23 | ## To Explore
24 |
25 | - `assembly/main.ts` for the contract code
26 | - `src/index.html` for the front-end HTML
27 | - `src/main.js` for the JavaScript front-end code and how to integrate contracts
28 | - `src/test.js` for the JS tests for the contract
29 |
30 |
31 | ## Data collection
32 |
33 | By using Gitpod in this project, you agree to opt-in to basic, anonymous analytics. No personal information is transmitted. Instead, these usage statistics aid in discovering potential bugs and user flow information.
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "counter",
3 | "description": "An Assemblyscript counter that lives in the NEAR blockchain",
4 | "version": "1.1.0",
5 | "scripts": {
6 | "build": "cd contract && npm run build && mkdir -p ../out && rm -f ./out/counter.wasm && cp ./build/release/counter_contract.wasm ../out/main.wasm",
7 | "deploy": "npm run build && near dev-deploy",
8 | "start": "npm run deploy && echo The app is starting! && env-cmd -f ./neardev/dev-account.env parcel frontend/index.html --open",
9 | "dev": "nodemon --watch contract -e ts --exec \"npm run start\"",
10 | "test": "npm run build && npm run test:unit && npm run test:integration",
11 | "test:unit": "cd contract && npm i && npm run test",
12 | "test:integration": "npm run test:integration:ts && npm run test:integration:rs",
13 | "test:integration:ts": "ava --verbose",
14 | "test:integration:rs": "cd integration-tests/rs && cargo run --example integration-tests"
15 | },
16 | "devDependencies": {
17 | "near-sdk-as": "3.2.3",
18 | "near-cli": "^3.2.0",
19 | "nodemon": "~2.0.15",
20 | "parcel-bundler": "~1.12.5",
21 | "ava": "^4.2.0",
22 | "near-workspaces": "^3.1.0",
23 | "typescript": "^4.6.4",
24 | "ts-node": "^10.7.0",
25 | "env-cmd": "^10.1.0"
26 | },
27 | "dependencies": {
28 | "near-api-js": "^0.44.2",
29 | "regenerator-runtime": "^0.13.9"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/contract/assembly/__tests__/main.spec.ts:
--------------------------------------------------------------------------------
1 | import { get_num, reset, increment, decrement } from '../index';
2 | import { context, storage } from 'near-sdk-as';
3 |
4 | describe("Counter ", () => {
5 | it("should increment by one", () => {
6 | increment();
7 | expect(get_num()).toBe(1, "counter should be one after a single increment.");
8 | });
9 |
10 | it("get_num is the same as reading from storage", () => {
11 | expect(storage.getPrimitive("counter", 0)).toBe(get_num(), "storage.getPrimitive(\"counter\", 0) = get_num()");
12 | });
13 |
14 | it("should decrement by one", () => {
15 | increment();
16 | decrement();
17 | expect(get_num()).toBe(0, "counter should be zero after a single decrement.");
18 | });
19 |
20 | it("should be resettable", () => {
21 | increment();
22 | increment();
23 | reset(); // reset to zero
24 | expect(get_num()).toBe(0, "counter should be zero after it is reset.");
25 | });
26 |
27 | it("should increment multiple times and decrement back to zero", () => {
28 | increment();
29 | expect(get_num()).toBe(1, "increment failed");
30 | increment();
31 | expect(get_num()).toBe(2, "increment failed");
32 | decrement();
33 | expect(get_num()).toBe(1, "increment failed");
34 | });
35 |
36 | it("should not overflow", () => {
37 | storage.set("counter", 127)
38 | expect(() => {increment()}).toThrow();
39 | });
40 |
41 | it("should not underflow", () => {
42 | storage.set("counter", -128)
43 | expect(() => {decrement()}).toThrow();
44 | });
45 | });
--------------------------------------------------------------------------------
/frontend/assets/js/near/config.js:
--------------------------------------------------------------------------------
1 | // Once you deploy the contract to its final account, make sure to specify it here
2 | const CONTRACT_NAME = process.env.CONTRACT_NAME || 'change_this_account'; /* TODO: Change this to the deployed account */
3 |
4 | function getConfig (env) {
5 | switch (env) {
6 | case 'production':
7 | case 'mainnet':
8 | return {
9 | networkId: 'mainnet',
10 | nodeUrl: 'https://rpc.mainnet.near.org',
11 | contractName: CONTRACT_NAME,
12 | walletUrl: 'https://wallet.near.org',
13 | helperUrl: 'https://helper.mainnet.near.org'
14 | }
15 | case 'development':
16 | case 'testnet':
17 | return {
18 | networkId: 'testnet',
19 | nodeUrl: 'https://rpc.testnet.near.org',
20 | contractName: CONTRACT_NAME,
21 | walletUrl: 'https://wallet.testnet.near.org',
22 | helperUrl: 'https://helper.testnet.near.org'
23 | }
24 | case 'betanet':
25 | return {
26 | networkId: 'betanet',
27 | nodeUrl: 'https://rpc.betanet.near.org',
28 | contractName: CONTRACT_NAME,
29 | walletUrl: 'https://wallet.betanet.near.org',
30 | helperUrl: 'https://helper.betanet.near.org'
31 | }
32 | case 'local':
33 | return {
34 | networkId: 'local',
35 | nodeUrl: 'http://localhost:3030',
36 | keyPath: `${process.env.HOME}/.near/validator_key.json`,
37 | walletUrl: 'http://localhost:4000/wallet',
38 | contractName: CONTRACT_NAME
39 | }
40 | case 'test':
41 | case 'ci':
42 | return {
43 | networkId: 'shared-test',
44 | nodeUrl: 'https://rpc.ci-testnet.near.org',
45 | contractName: CONTRACT_NAME,
46 | masterAccount: 'test.near'
47 | }
48 | case 'ci-betanet':
49 | return {
50 | networkId: 'shared-test-staging',
51 | nodeUrl: 'https://rpc.ci-betanet.near.org',
52 | contractName: CONTRACT_NAME,
53 | masterAccount: 'test.near'
54 | }
55 | default:
56 | throw Error(`Unconfigured environment '${env}'. Can be configured in src/config.js.`)
57 | }
58 | }
59 |
60 | module.exports = getConfig
61 |
--------------------------------------------------------------------------------
/integration-tests/ts/main.ava.ts:
--------------------------------------------------------------------------------
1 | import { Worker, NEAR, NearAccount } from "near-workspaces";
2 | import anyTest, { TestFn } from "ava";
3 |
4 | const test = anyTest as TestFn<{
5 | worker: Worker;
6 | accounts: Record;
7 | }>;
8 |
9 | test.beforeEach(async (t) => {
10 | // Init the worker and start a Sandbox server
11 | const worker = await Worker.init();
12 |
13 | // deploy contract
14 | const root = worker.rootAccount;
15 | const contract = await root.devDeploy(
16 | "./out/main.wasm",
17 | { initialBalance: NEAR.parse("30 N").toJSON() }
18 | );
19 |
20 | // some test accounts
21 | const alice = await root.createSubAccount("alice", {
22 | initialBalance: NEAR.parse("30 N").toJSON(),
23 | });
24 | const bob = await root.createSubAccount("bob", {
25 | initialBalance: NEAR.parse("30 N").toJSON(),
26 | });
27 | const charlie = await root.createSubAccount("charlie", {
28 | initialBalance: NEAR.parse("30 N").toJSON(),
29 | });
30 |
31 | // Save state for test runs, it is unique for each test
32 | t.context.worker = worker;
33 | t.context.accounts = { root, contract, alice, bob, charlie };
34 | });
35 |
36 | test.afterEach(async (t) => {
37 | // Stop Sandbox server
38 | await t.context.worker.tearDown().catch((error) => {
39 | console.log("Failed to stop the Sandbox:", error);
40 | });
41 | });
42 |
43 | test("can be incremented", async (t) => {
44 | const { root, contract } = t.context.accounts;
45 | const startCounter: number = await contract.view("get_num", {});
46 | await root.call(contract, "increment", {});
47 | const endCounter = await contract.view("get_num", {});
48 | t.is(endCounter, startCounter + 1);
49 | });
50 |
51 | test("can be decremented", async (t) => {
52 | const { root, contract } = t.context.accounts;
53 | await root.call(contract, "increment", {});
54 | const startCounter: number = await contract.view("get_num", {});
55 | await root.call(contract, "decrement", {});
56 | const endCounter = await contract.view("get_num", {});
57 | t.is(endCounter, startCounter - 1);
58 | });
59 |
60 | test("can be reset", async (t) => {
61 | const { root, contract } = t.context.accounts;
62 | await root.call(contract, "increment", {});
63 | await root.call(contract, "increment", {});
64 | await root.call(contract, "reset", {});
65 | const endCounter = await contract.view("get_num", {});
66 | t.is(endCounter, 0);
67 | });
68 |
--------------------------------------------------------------------------------
/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
This counter lives in the NEAR blockchain!
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
You'll need to sign in to interact with the counter:
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/frontend/assets/js/main.js:
--------------------------------------------------------------------------------
1 | import "regenerator-runtime/runtime";
2 | import { initContract, login, logout, getCounter, counterIncrement,
3 | counterDecrement, counterReset } from './near/utils'
4 |
5 | function resetUI(){
6 | document.querySelector('#show').classList.replace('number','loader');
7 | document.querySelector('#show').innerText = '';
8 | }
9 |
10 | // Animations
11 | document.querySelector('#c').addEventListener('click', () => {
12 | document.querySelector('#left').classList.toggle('eye');
13 | });
14 | document.querySelector('#b').addEventListener('click', () => {
15 | document.querySelector('#right').classList.toggle('eye');
16 | });
17 | document.querySelector('#d').addEventListener('click', () => {
18 | document.querySelector('.dot').classList.toggle('on');
19 | });
20 |
21 | // Buttons - Interact with the Smart Contract
22 | document.querySelector('#plus').addEventListener('click', async () => {
23 | resetUI();
24 | await counterIncrement();
25 | await updateUI();
26 | });
27 |
28 | document.querySelector('#minus').addEventListener('click', async () => {
29 | resetUI();
30 | await counterDecrement();
31 | await updateUI();
32 | });
33 | document.querySelector('#a').addEventListener('click', async () => {
34 | resetUI();
35 | await counterReset();
36 | await updateUI();
37 | });
38 |
39 | // Log in and log out users using NEAR Wallet
40 | document.querySelector('.sign-in .btn').onclick = login;
41 | document.querySelector('.sign-out .btn').onclick = logout;
42 |
43 | // `nearInitPromise` gets called on page load
44 | window.nearInitPromise = initContract()
45 | .then(flow)
46 | .catch(console.error)
47 |
48 | function flow(){
49 | if (window.walletConnection.isSignedIn()){
50 | signedInFlow()
51 | }else{
52 | signedOutFlow()
53 | }
54 | updateUI()
55 | }
56 |
57 | // Display the signed-out-flow container
58 | function signedOutFlow() {
59 | document.querySelector('.sign-in').style.display = 'block';
60 | document.querySelectorAll('.interact').forEach(button => button.disabled = true)
61 | }
62 |
63 | // Displaying the signed in flow container and display counter
64 | async function signedInFlow() {
65 | document.querySelector('.sign-out').style.display = 'block';
66 | document.querySelectorAll('.interact').forEach(button => button.disabled = false)
67 | }
68 |
69 | async function updateUI(){
70 | let count = await getCounter();
71 |
72 | document.querySelector('#show').classList.replace('loader','number');
73 | document.querySelector('#show').innerText = count === undefined ? 'calculating...' : count;
74 | document.querySelector('#left').classList.toggle('eye');
75 |
76 | if (count >= 0) {
77 | document.querySelector('.mouth').classList.replace('cry','smile');
78 | } else {
79 | document.querySelector('.mouth').classList.replace('smile','cry');
80 | }
81 |
82 | if (count > 20 || count < -20) {
83 | document.querySelector('.tongue').style.display = 'block';
84 | } else {
85 | document.querySelector('.tongue').style.display = 'none';
86 | }
87 | }
--------------------------------------------------------------------------------
/frontend/assets/js/near/utils.js:
--------------------------------------------------------------------------------
1 | import { connect, Contract, keyStores, WalletConnection } from 'near-api-js'
2 | import getConfig from './config'
3 |
4 | const nearConfig = getConfig(process.env.NODE_ENV || 'development')
5 |
6 | // Initialize contract & set global variables
7 | export async function initContract() {
8 | // Initialize connection to the NEAR testnet
9 | const near = await connect(Object.assign({ deps: { keyStore: new keyStores.BrowserLocalStorageKeyStore() } }, nearConfig))
10 |
11 | // Initializing Wallet based Account. It can work with NEAR testnet wallet that
12 | // is hosted at https://wallet.testnet.near.org
13 | window.walletConnection = new WalletConnection(near)
14 |
15 | // Getting the Account ID. If still unauthorized, it's just empty string
16 | window.accountId = window.walletConnection.getAccountId()
17 |
18 | // Initializing our contract APIs by contract name and configuration
19 | window.contract = await new Contract(window.walletConnection.account(), nearConfig.contractName, {
20 | // View methods are read only. They don't modify the state, but usually return some value.
21 | viewMethods: ['get_num'],
22 | // Change methods can modify the state. But you don't receive the returned value when called.
23 | changeMethods: ['increment', 'decrement', 'reset'],
24 | })
25 | }
26 |
27 | export function logout() {
28 | window.walletConnection.signOut()
29 | // reload page
30 | window.location.replace(window.location.origin + window.location.pathname)
31 | }
32 |
33 | export function login() {
34 | // Allow the current app to make calls to the specified contract on the
35 | // user's behalf.
36 | // This works by creating a new access key for the user's account and storing
37 | // the private key in localStorage.
38 | window.walletConnection.requestSignIn(nearConfig.contractName)
39 | }
40 |
41 | export async function getCounter(){
42 | let count = await window.contract.get_num({args:{}})
43 | .catch(err => errorHelper(err))
44 | return count;
45 | }
46 |
47 | export async function counterIncrement(){
48 | await window.contract.increment({args:{}})
49 | }
50 |
51 | export async function counterDecrement(){
52 | await window.contract.decrement({args:{}})
53 | }
54 |
55 | export async function counterReset(){
56 | await window.contract.reset({args:{}})
57 | }
58 |
59 | function errorHelper(err) {
60 | // if there's a cryptic error, provide more helpful feedback and instructions here
61 | // TODO: as soon as we get the error codes propagating back, use those
62 | if (err.message.includes('Cannot deserialize the contract state')) {
63 | console.warn('NEAR Warning: the contract/account seems to have state that is not (or no longer) compatible.\n' +
64 | 'This may require deleting and recreating the NEAR account as shown here:\n' +
65 | 'https://stackoverflow.com/a/60767144/711863');
66 | }
67 | if (err.message.includes('Cannot deserialize the contract state')) {
68 | console.warn('NEAR Warning: the contract/account seems to have state that is not (or no longer) compatible.\n' +
69 | 'This may require deleting and recreating the NEAR account as shown here:\n' +
70 | 'https://stackoverflow.com/a/60767144/711863');
71 | }
72 | console.error(err);
73 | }
74 |
--------------------------------------------------------------------------------
/integration-tests/rs/src/tests.rs:
--------------------------------------------------------------------------------
1 | use serde_json::json;
2 | use near_units::parse_near;
3 | use workspaces::prelude::*;
4 | use workspaces::{network::Sandbox, Account, Contract, Worker};
5 |
6 | const WASM_FILEPATH: &str = "../../out/main.wasm";
7 |
8 | #[tokio::main]
9 | async fn main() -> anyhow::Result<()> {
10 | let worker = workspaces::sandbox().await?;
11 | let wasm = std::fs::read(WASM_FILEPATH)?;
12 | let contract = worker.dev_deploy(&wasm).await?;
13 |
14 | // create accounts
15 | let owner = worker.root_account().unwrap();
16 | let alice = owner
17 | .create_subaccount(&worker, "alice")
18 | .initial_balance(parse_near!("30 N"))
19 | .transact()
20 | .await?
21 | .into_result()?;
22 |
23 | // begin tests
24 | test_increment(&alice, &contract, &worker).await?;
25 | test_decrement(&alice, &contract, &worker).await?;
26 | test_reset(&alice, &contract, &worker).await?;
27 | Ok(())
28 | }
29 |
30 | async fn test_increment(
31 | user: &Account,
32 | contract: &Contract,
33 | worker: &Worker,
34 | ) -> anyhow::Result<()> {
35 | let start_counter: u64 = user
36 | .call(&worker, contract.id(), "get_num")
37 | .args_json(json!({}))?
38 | .transact()
39 | .await?
40 | .json()?;
41 |
42 | user
43 | .call(&worker, contract.id(), "increment")
44 | .args_json(json!({}))?
45 | .transact()
46 | .await?;
47 |
48 | let end_counter: u64 = user
49 | .call(&worker, contract.id(), "get_num")
50 | .args_json(json!({}))?
51 | .transact()
52 | .await?
53 | .json()?;
54 |
55 | assert_eq!(end_counter, start_counter + 1);
56 | println!(" Passed ✅ can be incremented");
57 | Ok(())
58 | }
59 |
60 | async fn test_decrement(
61 | user: &Account,
62 | contract: &Contract,
63 | worker: &Worker,
64 | ) -> anyhow::Result<()> {
65 | user
66 | .call(&worker, contract.id(), "increment")
67 | .args_json(json!({}))?
68 | .transact()
69 | .await?;
70 |
71 | let start_counter: u64 = user
72 | .call(&worker, contract.id(), "get_num")
73 | .args_json(json!({}))?
74 | .transact()
75 | .await?
76 | .json()?;
77 |
78 | user
79 | .call(&worker, contract.id(), "decrement")
80 | .args_json(json!({}))?
81 | .transact()
82 | .await?;
83 |
84 | let end_counter: u64 = user
85 | .call(&worker, contract.id(), "get_num")
86 | .args_json(json!({}))?
87 | .transact()
88 | .await?
89 | .json()?;
90 |
91 | assert_eq!(end_counter, start_counter - 1);
92 | println!(" Passed ✅ can be decremented");
93 | Ok(())
94 | }
95 |
96 | async fn test_reset(
97 | user: &Account,
98 | contract: &Contract,
99 | worker: &Worker,
100 | ) -> anyhow::Result<()> {
101 | user
102 | .call(&worker, contract.id(), "increment")
103 | .args_json(json!({}))?
104 | .transact()
105 | .await?;
106 |
107 | user
108 | .call(&worker, contract.id(), "increment")
109 | .args_json(json!({}))?
110 | .transact()
111 | .await?;
112 |
113 | user
114 | .call(&worker, contract.id(), "reset")
115 | .args_json(json!({}))?
116 | .transact()
117 | .await?;
118 |
119 | let end_counter: u64 = user
120 | .call(&worker, contract.id(), "get_num")
121 | .args_json(json!({}))?
122 | .transact()
123 | .await?
124 | .json()?;
125 |
126 | assert_eq!(end_counter, 0);
127 | println!(" Passed ✅ can be reset");
128 | Ok(())
129 | }
--------------------------------------------------------------------------------
/frontend/assets/css/global.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | margin-top: 1em !important;
3 | margin-bottom: 1em !important;
4 | text-align: center;
5 | }
6 |
7 | .scene {
8 | height: 350px;
9 | }
10 | .face {
11 | margin: auto;
12 | width: 66%;
13 | height: 72%;
14 | background-color: #fffaf2;
15 | }
16 | .number {
17 | text-align: center;
18 | margin:auto;
19 | width: 66%;
20 | height: 28%;
21 | background-color: #ffd9f8;
22 | border-top: 5px dotted #82174d;
23 | font-size:1.5rem;
24 | }
25 | .eyes-row {
26 | display: flex;
27 | justify-content: space-around;
28 | margin-top: 24%;
29 | padding: 0 8px;
30 | }
31 | .closed {
32 | width: 22px;
33 | height: 13px;
34 | border-top-left-radius: 100px;
35 | border-top-right-radius: 100px;
36 | border-left: 2px solid #ffa4b1;
37 | border-right: 2px solid #ffa4b1;
38 | border-top: 2px solid #ffa4b1;
39 | margin-bottom: 12px;
40 | }
41 | .eye {
42 | width: 26px;
43 | height: 26px;
44 | border-radius: 100px;
45 | background-color: #ffa4b1;
46 | display: flex;
47 | justify-content: center;
48 | align-items: center;
49 | margin-bottom: 1px;
50 | }
51 | .eye .pupil {
52 | position: relative;
53 | width: 18px;
54 | height: 18px;
55 | border-radius: 100px;
56 | background-color: #82174d;
57 | }
58 | .eye .pupil:before {
59 | content: "";
60 | width: 6px;
61 | height: 6px;
62 | position: absolute;
63 | background-color: #fff;
64 | top: 4px;
65 | left: 3px;
66 | border-radius: 100px;
67 | }
68 | .eye .pupil:after {
69 | content: "";
70 | width: 3px;
71 | height: 3px;
72 | position: absolute;
73 | background-color: #fff;
74 | top: 9px;
75 | left: 12px;
76 | border-radius: 100px;
77 | }
78 | .mouth-row {
79 | display: flex;
80 | flex-direction: column;
81 | justify-content: space-around;
82 | align-items: center;
83 | }
84 | .mouth-row .mouth {
85 | margin-top: 3%;
86 | }
87 | .mouth-row .tongue {
88 | position:absolute;
89 | width: 10px;
90 | height: 10px;
91 | background-color: #FF585D;
92 | border-radius: 50% 50% 30%;
93 | margin: 5px 0;
94 | }
95 | .mouth-row .mouth.smile {
96 | height: 16px;
97 | width: 32px;
98 | border-bottom-left-radius: 32px;
99 | border-bottom-right-radius: 32px;
100 | background-color: #82174d;
101 | top: 120px;
102 | }
103 | .mouth-row .mouth.cry {
104 | height: 16px;
105 | width: 32px;
106 | border-top-left-radius: 32px;
107 | border-top-right-radius: 32px;
108 | background-color: #82174d;
109 | top: 120px;
110 | }
111 | .mouth-row .mouth:before {
112 | content: "";
113 | left: 43px;
114 | margin-top: 1%;
115 | border-radius: 100%;
116 | height: 5%;
117 | width: 11.5%;
118 | background-color: #f56f79;
119 | position: absolute;
120 | }
121 | .mouth-row .mouth:after {
122 | content: "";
123 | left: 106px;
124 | margin-top: 1%;
125 | border-radius: 100%;
126 | height: 5%;
127 | width: 11.5%;
128 | background-color: #f56f79;
129 | position: absolute;
130 | }
131 | .gameboy {
132 | position: relative;
133 | width: 400px;
134 | margin: auto;
135 | }
136 | .body-shape {
137 | position: absolute;
138 | height: 300px;
139 | width: 205px;
140 | border-radius: 15px;
141 | }
142 | .body-shape .shadow {
143 | height: 290px;
144 | }
145 | .body-shape .screen {
146 | margin: 20px;
147 | position: relative;
148 | width: 168px;
149 | height: 134px;
150 | background-color: #82174d;
151 | border-radius: 4px;
152 | display: flex;
153 | flex-direction: column;
154 | justify-items: center;
155 | }
156 | .body-shape .dot {
157 | content: "";
158 | width: 8px;
159 | height: 8px;
160 | position: absolute;
161 | background-color: #ffa4b1;
162 | top: 40px;
163 | left: 10px;
164 | border-radius: 100px;
165 | }
166 | .body-shape .on {
167 | background-color: #F0EC74;
168 | }
169 | .body-shape .buttons {
170 | display: flex;
171 | flex-direction: column;
172 | justify-content: space-around;
173 | width: 100%;
174 | }
175 | .body-shape .buttons .row {
176 | display: flex;
177 | }
178 | .body-shape .buttons .selects {
179 | margin-top: 10px;
180 | padding-left: 140px;
181 | }
182 | .body-shape .buttons .arrows {
183 | position: relative;
184 | height: 40px;
185 | width: 40px;
186 | border-radius: 100px;
187 | background-color: #ffa4b1;
188 | margin-left: 30px;
189 | padding: 0;
190 | cursor: grab;
191 | }
192 | .body-shape .buttons .arrows:disabled {
193 | opacity: 0.8;
194 | background-color: #d18892;
195 | }
196 | .body-shape .buttons .arrows .updown {
197 | position: relative;
198 | height: 35px;
199 | width: 10px;
200 | background-color: #82174d;
201 | border-radius: 2px;
202 | top: -8px;
203 | left: 14px;
204 | }
205 | .body-shape .buttons .arrows .left {
206 | position: relative;
207 | width: 35px;
208 | height: 10px;
209 | background-color: #82174d;
210 | border-radius: 2px;
211 | top: 14px;
212 | left: 2px;
213 | }
214 | .body-shape .buttons .arrows .right {
215 | position: relative;
216 | width: 35px;
217 | height: 10px;
218 | background-color: #82174d;
219 | border-radius: 2px;
220 | left: 2px;
221 | }
222 | .body-shape .buttons .ab {
223 | width: 64px;
224 | height: 64px;
225 | background-color: #ffa4b1;
226 | border-radius: 10px;
227 | transform: rotate(45deg);
228 | font-size: 0.6rem;
229 | text-align: center;
230 | }
231 | .body-shape .buttons .ab .r {
232 | width: 24px;
233 | height: 24px;
234 | border-radius: 100%;
235 | background-color: #82174d;
236 | position: absolute;
237 | transform: rotate(-45deg);
238 | padding: 5px;
239 | color: #ffa4b1;
240 | cursor:pointer;
241 | box-shadow:-1px 0 1px #4B4F54;
242 | }
243 | .body-shape .buttons .ab .r:hover {
244 | opacity: 0.8;
245 | }
246 | .body-shape .buttons .ab .r:active {
247 | background-color: #F0EC74;
248 | opacity: 1;
249 | }
250 | .body-shape .buttons .ab .a {
251 | top: 4px;
252 | left: 4px;
253 | }
254 | .body-shape .buttons .ab .b {
255 | top: 4px;
256 | left: 36px;
257 | }
258 | .body-shape .buttons .ab .c {
259 | top: 36px;
260 | left: 4px;
261 | }
262 | .body-shape .buttons .ab .d {
263 | top: 36px;
264 | left: 36px;
265 | }
266 | .shadow {
267 | background-color: #888ad0;
268 | z-index: 0;
269 | left: -17px;
270 | top: 26px;
271 | }
272 | .side {
273 | background-color: #82174d;
274 | z-index: 1;
275 | }
276 | .front {
277 | background-color: #f56f79;
278 | left: 26px;
279 | z-index: 2;
280 | }
281 | .loader,
282 | .loader:before,
283 | .loader:after {
284 | background: #f56f79;
285 | -webkit-animation: load1 1s infinite ease-in-out;
286 | animation: load1 1s infinite ease-in-out;
287 | width: 0.4rem;
288 | height: 4em;
289 | }
290 | .loader {
291 | color: #f56f79;
292 | margin: 2px auto;
293 | font-size: 0.2rem;
294 | -webkit-transform: translateZ(0);
295 | -ms-transform: translateZ(0);
296 | transform: translateZ(0);
297 | -webkit-animation-delay: -0.16s;
298 | animation-delay: -0.16s;
299 | }
300 | .loader:before,
301 | .loader:after {
302 | position: absolute;
303 | top: 0;
304 | content: '';
305 | }
306 | .loader:before {
307 | left: -1.5em;
308 | -webkit-animation-delay: -0.32s;
309 | animation-delay: -0.32s;
310 | }
311 | .loader:after {
312 | left: 1.5em;
313 | }
314 | @-webkit-keyframes load1 {
315 | 0%,
316 | 80%,
317 | 100% {
318 | box-shadow: 0 0;
319 | height: 2em;
320 | }
321 | 40% {
322 | box-shadow: 0 -2em;
323 | height: 3em;
324 | }
325 | }
326 | @keyframes load1 {
327 | 0%,
328 | 80%,
329 | 100% {
330 | box-shadow: 0 0;
331 | height: 2em;
332 | }
333 | 40% {
334 | box-shadow: 0 -2em;
335 | height: 3em;
336 | }
337 | }
--------------------------------------------------------------------------------
/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
--------------------------------------------------------------------------------