├── README.md ├── sensors-data ├── Makefile ├── index.js ├── .dockerignore ├── Dockerfile ├── tsconfig.json ├── package.json ├── src │ └── index.ts └── yarn.lock ├── json-rest-api-cors-enabled ├── Makefile ├── Dockerfile ├── package.json └── index.js ├── diagnostics ├── DIAGNOSTICS.png ├── Dockerfile ├── Dockerfile-arm ├── Makefile ├── README.md └── diagnostic.py ├── JSON-Generator ├── Dockerfile ├── Dockerfile-arm ├── package.json ├── Makefile ├── example.json └── jsonGenerator.js ├── JSON-REST-API ├── Dockerfile ├── Dockerfile-arm ├── package.json ├── Makefile └── jsonRestApi.js ├── OpenWeatherMap ├── Dockerfile ├── Dockerfile-arm ├── package.json ├── Makefile └── openWeatherMap.js ├── JSON-Subselect ├── nodejs_version │ ├── Dockerfile │ ├── Dockerfile-arm │ ├── package.json │ ├── Makefile │ └── jsonSubselect.js ├── java_version │ ├── json_subselect.jar │ ├── iofog-java-sdk-0.0.1.jar │ ├── Dockerfile │ ├── Dockerfile-arm │ ├── Makefile │ ├── src │ │ └── org │ │ │ └── eclipse │ │ │ └── iofog │ │ │ ├── IOFogAPIListenerImpl.java │ │ │ └── JSONSubselectMain.java │ └── pom.xml ├── python_version │ ├── Dockerfile │ ├── Dockerfile-arm │ ├── Makefile │ └── main.py └── go_version │ ├── Dockerfile │ ├── Dockerfile-arm │ ├── Makefile │ └── subselect.go ├── humidity_sensor_simulator ├── Dockerfile ├── Dockerfile-arm ├── Makefile └── index.py ├── seismic_sensor_simulator ├── Dockerfile ├── Dockerfile-arm ├── Makefile └── index.py ├── Temperature-Conversion ├── nodejs_version │ ├── Dockerfile │ ├── Dockerfile-arm │ ├── package.json │ ├── Makefile │ └── tempConversion.js ├── Dockerfile ├── Dockerfile-arm ├── Makefile └── index.py ├── temperature_sensor_simulator ├── Dockerfile ├── Dockerfile-arm ├── Makefile └── index.py ├── freeboard ├── Dockerfile └── dashboard.json ├── NOTICE ├── CONTRIBUTING └── .gitignore /README.md: -------------------------------------------------------------------------------- 1 | # example-microservices -------------------------------------------------------------------------------- /sensors-data/Makefile: -------------------------------------------------------------------------------- 1 | image: 2 | docker build -t baghbidi/public:sensors . -------------------------------------------------------------------------------- /sensors-data/index.js: -------------------------------------------------------------------------------- 1 | require('ts-node/register') 2 | require('./src/index') -------------------------------------------------------------------------------- /json-rest-api-cors-enabled/Makefile: -------------------------------------------------------------------------------- 1 | image: 2 | docker build -t baghbidi/public:freeboard-api . -------------------------------------------------------------------------------- /sensors-data/.dockerignore: -------------------------------------------------------------------------------- 1 | **/** 2 | !package.json 3 | !index.js 4 | !tsconfig.json 5 | !src 6 | !data -------------------------------------------------------------------------------- /diagnostics/DIAGNOSTICS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-iofog/example-microservices/HEAD/diagnostics/DIAGNOSTICS.png -------------------------------------------------------------------------------- /diagnostics/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/python 2 | 3 | COPY diagnostic.py /src/ 4 | WORKDIR /src 5 | CMD ["python", "diagnostic.py"] 6 | -------------------------------------------------------------------------------- /JSON-Generator/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/nodejs 2 | 3 | COPY . /src 4 | RUN cd /src; npm install 5 | 6 | CMD ["node","/src/jsonGenerator.js"] -------------------------------------------------------------------------------- /JSON-REST-API/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/nodejs 2 | 3 | COPY . /src 4 | RUN cd /src; npm install 5 | 6 | CMD ["node","/src/jsonRestApi.js"] -------------------------------------------------------------------------------- /diagnostics/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | FROM iofog/python-arm 2 | 3 | COPY diagnostic.py /src/ 4 | WORKDIR /src 5 | CMD ["python", "diagnostic.py"] 6 | -------------------------------------------------------------------------------- /sensors-data/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | COPY . /sensors 4 | WORKDIR /sensors 5 | RUN npm i 6 | 7 | CMD [ "node", "/sensors/index" ] -------------------------------------------------------------------------------- /OpenWeatherMap/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/nodejs 2 | 3 | COPY . /src 4 | RUN cd /src; npm install 5 | 6 | CMD ["node","/src/openWeatherMap.js"] 7 | -------------------------------------------------------------------------------- /JSON-Subselect/nodejs_version/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/nodejs 2 | 3 | COPY . /src 4 | RUN cd /src; npm install 5 | 6 | CMD ["node","/src/jsonSubselect.js"] -------------------------------------------------------------------------------- /humidity_sensor_simulator/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/python 2 | 3 | COPY index.py /src/ 4 | RUN cd /src; 5 | 6 | CMD ["python", "/src/index.py", "--log", "DEBUG"] -------------------------------------------------------------------------------- /seismic_sensor_simulator/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/python 2 | 3 | COPY index.py /src/ 4 | RUN cd /src; 5 | 6 | CMD ["python", "/src/index.py", "--log", "DEBUG"] -------------------------------------------------------------------------------- /JSON-Subselect/java_version/json_subselect.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-iofog/example-microservices/HEAD/JSON-Subselect/java_version/json_subselect.jar -------------------------------------------------------------------------------- /Temperature-Conversion/nodejs_version/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/nodejs 2 | 3 | COPY . /src 4 | RUN cd /src; npm install 5 | 6 | CMD ["node","/src/tempConversion.js"] -------------------------------------------------------------------------------- /temperature_sensor_simulator/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/python 2 | 3 | COPY index.py /src/ 4 | RUN cd /src; 5 | 6 | CMD ["python", "/src/index.py", "--log", "DEBUG"] -------------------------------------------------------------------------------- /JSON-Generator/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | #for RaspberryPi 2 | FROM iofog/nodejs-arm 3 | 4 | COPY . /src 5 | RUN cd /src; npm install 6 | 7 | CMD ["node","/src/jsonGenerator.js"] -------------------------------------------------------------------------------- /JSON-REST-API/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | #for RaspberryPi 2 | FROM iofog/nodejs-arm 3 | 4 | COPY . /src 5 | RUN cd /src; npm install 6 | 7 | CMD ["node","/src/jsonRestApi.js"] -------------------------------------------------------------------------------- /humidity_sensor_simulator/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | FROM iofog/python-arm 2 | 3 | COPY index.py /src/ 4 | RUN cd /src; 5 | 6 | CMD ["python", "/src/index.py", "--log", "DEBUG"] -------------------------------------------------------------------------------- /seismic_sensor_simulator/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | FROM iofog/python-arm 2 | 3 | COPY index.py /src/ 4 | RUN cd /src; 5 | 6 | CMD ["python", "/src/index.py", "--log", "DEBUG"] -------------------------------------------------------------------------------- /OpenWeatherMap/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | #for RaspberryPi 2 | FROM iofog/nodejs-arm 3 | 4 | COPY . /src 5 | RUN cd /src; npm install 6 | 7 | CMD ["node","/src/openWeatherMap.js"] 8 | -------------------------------------------------------------------------------- /temperature_sensor_simulator/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | FROM iofog/python-arm 2 | 3 | COPY index.py /src/ 4 | RUN cd /src; 5 | 6 | CMD ["python", "/src/index.py", "--log", "DEBUG"] -------------------------------------------------------------------------------- /JSON-Subselect/java_version/iofog-java-sdk-0.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipse-iofog/example-microservices/HEAD/JSON-Subselect/java_version/iofog-java-sdk-0.0.1.jar -------------------------------------------------------------------------------- /JSON-Subselect/nodejs_version/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | #for RaspberryPi 2 | FROM iofog/nodejs-arm 3 | 4 | COPY . /src 5 | RUN cd /src; npm install 6 | 7 | CMD ["node","/src/jsonSubselect.js"] -------------------------------------------------------------------------------- /JSON-Subselect/python_version/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/python 2 | 3 | RUN pip install jsonpath-rw 4 | 5 | COPY . /src 6 | RUN cd /src; 7 | 8 | CMD ["python", "/src/main.py", "--log", "DEBUG"] -------------------------------------------------------------------------------- /Temperature-Conversion/nodejs_version/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | #for RaspberryPi 2 | FROM iofog/nodejs-arm 3 | 4 | COPY . /src 5 | RUN cd /src; npm install 6 | 7 | CMD ["node","/src/tempConversion.js"] -------------------------------------------------------------------------------- /JSON-Subselect/python_version/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | FROM iofog/python-arm 2 | 3 | RUN pip install jsonpath-rw 4 | 5 | COPY . /src 6 | RUN cd /src; 7 | 8 | CMD ["python", "/src/main.py", "--log", "DEBUG"] -------------------------------------------------------------------------------- /Temperature-Conversion/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/python 2 | 3 | RUN pip install jsonpath-rw 4 | 5 | COPY index.py /src/ 6 | RUN cd /src; 7 | 8 | CMD ["python", "/src/index.py", "--log", "DEBUG"] 9 | -------------------------------------------------------------------------------- /JSON-Subselect/java_version/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jeanblanchard/java:jdk-8u77 2 | 3 | RUN mkdir /jar-file 4 | COPY . /jar-file 5 | RUN cd /jar-file 6 | 7 | CMD ["java", "-jar", "/jar-file/json_subselect.jar"] 8 | -------------------------------------------------------------------------------- /Temperature-Conversion/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | FROM iofog/python-arm 2 | 3 | RUN pip install jsonpath-rw 4 | 5 | COPY index.py /src/ 6 | RUN cd /src; 7 | 8 | CMD ["python", "/src/index.py", "--log", "DEBUG"] 9 | -------------------------------------------------------------------------------- /JSON-Subselect/java_version/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | FROM maxleiko/armhf-alpine-java 2 | 3 | RUN mkdir /jar-file 4 | COPY . /jar-file 5 | RUN cd /jar-file 6 | 7 | CMD ["java", "-jar", "/jar-file/json_subselect.jar"] 8 | 9 | -------------------------------------------------------------------------------- /json-rest-api-cors-enabled/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iofog/nodejs 2 | #for RaspberryPi 3 | #FROM iofog/nodejs-arm 4 | 5 | COPY index.js /src/index.js 6 | COPY package.json /src/package.json 7 | RUN cd /src; npm install 8 | 9 | CMD [ "node", "/src/index.js" ] 10 | -------------------------------------------------------------------------------- /json-rest-api-cors-enabled/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "freeboard-JSON-provider", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "Saeid Baghbidi", 6 | "license": "EPL-2.0", 7 | "dependencies": { 8 | "@iofog/nodejs-sdk": "0.0.1", 9 | "http": "0.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /freeboard/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:stable-alpine 2 | 3 | COPY dashboard.json /usr/share/nginx/html/dashboard.json 4 | 5 | RUN apk --no-cache add ca-certificates wget tar \ 6 | && wget -O freeboard.tar.gz https://api.github.com/repos/Freeboard/freeboard/tarball/master \ 7 | && tar -xzvf freeboard.tar.gz -C /usr/share/nginx/html --strip-components=1 8 | -------------------------------------------------------------------------------- /JSON-Generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JsonGenerator", 3 | "version": "1.0.0", 4 | "description": "Container generates ioMessages with contentdata as complex JSON object.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/ioFog/example-microservices.git" 8 | }, 9 | "author": "Eclipse ioFog", 10 | "license": "EPL-2.0", 11 | "dependencies": { 12 | "@iofog/nodejs-sdk": "0.0.x" 13 | } 14 | } -------------------------------------------------------------------------------- /JSON-Subselect/go_version/Dockerfile: -------------------------------------------------------------------------------- 1 | # Compile stage 2 | FROM golang:1.11.3-alpine3.8 AS build-env 3 | ENV CGO_ENABLED 0 4 | ADD . /go/src/subselect 5 | 6 | RUN apk add git gcc libc-dev 7 | 8 | RUN go get github.com/ioFog/iofog-go-sdk 9 | RUN go build -gcflags "-N -l" --ldflags '-linkmode "external" -extldflags "-static"' -x -o /subselect subselect 10 | 11 | FROM alpine:latest 12 | 13 | COPY --from=build-env /go/src/subselect /go/bin 14 | 15 | WORKDIR /go/bin 16 | CMD ["./subselect"] 17 | -------------------------------------------------------------------------------- /sensors-data/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "module": "commonjs", 5 | "target": "es5", 6 | "lib": ["es6"], 7 | "sourceMap": true, 8 | "allowJs": true, 9 | "moduleResolution": "node", 10 | "rootDir": ".", 11 | "noImplicitReturns": true, 12 | "noImplicitThis": true, 13 | "noImplicitAny": false, 14 | "strictNullChecks": true, 15 | }, 16 | "exclude": [ 17 | "node_modules", 18 | "dist", 19 | ], 20 | } -------------------------------------------------------------------------------- /OpenWeatherMap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "OpenWeatherMap", 3 | "version": "1.0.6", 4 | "description": "Grabs weather information from the Open Weather Map REST API and posts it as a message to ioFog.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/ioFog/example-microservices.git" 8 | }, 9 | "author": "Eclipse ioFog", 10 | "license": "EPL-2.0", 11 | "dependencies": { 12 | "request": "2.70.0", 13 | "@iofog/nodejs-sdk": "0.0.x" 14 | } 15 | } -------------------------------------------------------------------------------- /JSON-REST-API/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JsonRestApi", 3 | "version": "1.0.4", 4 | "description": "Receives messages and stores them. Provides REST API for outside systems to get the messages on request.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/ioFog/example-microservices.git" 8 | }, 9 | "author": "Eclipse ioFog", 10 | "license": "EPL-2.0", 11 | "dependencies": { 12 | "http": "0.0.0", 13 | "@iofog/nodejs-sdk": "0.0.x" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /JSON-Subselect/go_version/Dockerfile-arm: -------------------------------------------------------------------------------- 1 | # Compile stage 2 | FROM golang:1.11.3-alpine3.8 AS build-env 3 | ENV CGO_ENABLED 0 4 | ADD . /go/src/subselect 5 | 6 | RUN apk add git gcc libc-dev 7 | 8 | RUN go get github.com/ioFog/iofog-go-sdk 9 | RUN go build -gcflags "-N -l" --ldflags '-linkmode "external" -extldflags "-static"' -x -o /subselect subselect 10 | 11 | FROM hypriot/rpi-alpine-scratch 12 | 13 | COPY --from=build-env /go/src/subselect /go/bin 14 | 15 | WORKDIR /go/bin 16 | CMD ["./subselect"] -------------------------------------------------------------------------------- /JSON-Subselect/nodejs_version/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JsonSubselect", 3 | "version": "1.0.0", 4 | "description": "Container takes the portions of a JSON message that they want and publish the results as a new message with whatever ioMessage format they want.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/Edgeworx/commercialsuite.git" 8 | }, 9 | "author": "Eclipse ioFog", 10 | "license": "EPL-2.0", 11 | "dependencies": { 12 | "@iofog/nodejs-sdk": "0.0.x" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Temperature-Conversion/nodejs_version/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TemperatureConversion", 3 | "version": "1.0.0", 4 | "description": "Receives temperature messages, converts them to the desired output format, and if they pass transformation requirements publishes new messages with the desired format.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/ioFog/example-microservices.git" 8 | }, 9 | "author": "Eclipse ioFog", 10 | "license": "EPL-2.0", 11 | "dependencies": { 12 | "@iofog/nodejs-sdk": "0.0.x" 13 | } 14 | } -------------------------------------------------------------------------------- /sensors-data/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto-sensors", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@iofog/nodejs-sdk": "^0.0.1", 14 | "csv": "^4.0.0", 15 | "csv-parse": "^3.1.3", 16 | "path": "^0.12.7" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^10.12.0", 20 | "ts-node": "^7.0.1", 21 | "typescript": "^3.1.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /diagnostics/Makefile: -------------------------------------------------------------------------------- 1 | ## Build with version number for test purposes 2 | build: 3 | sudo docker build -t iofog/diagnostics:$(TAG) . 4 | ## Push with version number for test purposes 5 | push:build 6 | sudo docker push iofog/diagnostics:$(TAG) 7 | ## Tag latest to verified version number 8 | latest: 9 | sudo docker tag iofog/diagnostics:$(TAG) iofog/diagnostics 10 | ## Push latest 11 | push-latest:latest 12 | sudo docker push iofog/diagnostics 13 | ## Same cmds for arm 14 | build-arm: 15 | sudo docker build -t iofog/diagnostics-arm:$(TAG) -f Dockerfile-arm . 16 | push-arm:build-arm 17 | sudo docker push iofog/diagnostics-arm:$(TAG) 18 | latest-arm: 19 | sudo docker tag iofog/diagnostics-arm:$(TAG) iofog/diagnostics-arm 20 | push-latest-arm:latest-arm 21 | sudo docker push iofog/diagnostics-arm -------------------------------------------------------------------------------- /JSON-REST-API/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/json-rest-api 3 | DOCKER_IMAGE_NAME_ARM=iofog/json-rest-api-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /JSON-Generator/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/json-generator 3 | DOCKER_IMAGE_NAME_ARM=iofog/json-generator-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /OpenWeatherMap/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/open-weather-map 3 | DOCKER_IMAGE_NAME_ARM=iofog/open-weather-map-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /JSON-Subselect/go_version/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/json-subselect 3 | DOCKER_IMAGE_NAME_ARM=iofog/json-subselect-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /JSON-Subselect/java_version/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/json-subselect-java 3 | DOCKER_IMAGE_NAME_ARM=iofog/json-subselect-java-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /JSON-Subselect/nodejs_version/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/json-subselect-node 3 | DOCKER_IMAGE_NAME_ARM=iofog/json-subselect-node-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /Temperature-Conversion/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/temperature-conversion 3 | DOCKER_IMAGE_NAME_ARM=iofog/temperature-conversion-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /JSON-Subselect/python_version/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/json-subselect-python 3 | DOCKER_IMAGE_NAME_ARM=iofog/json-subselect-python-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /seismic_sensor_simulator/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/seismic-sensor-simulator 3 | DOCKER_IMAGE_NAME_ARM=iofog/seismic-sensor-simulator-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /humidity_sensor_simulator/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/humidity-sensor-simulator 3 | DOCKER_IMAGE_NAME_ARM=iofog/humidity-sensor-simulator-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /temperature_sensor_simulator/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/temperature-sensor-simulator 3 | DOCKER_IMAGE_NAME_ARM=iofog/temperature-sensor-simulator-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /Temperature-Conversion/nodejs_version/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE_VERSION=1.0 2 | DOCKER_IMAGE_NAME=iofog/temperature-conversion-node 3 | DOCKER_IMAGE_NAME_ARM=iofog/temperature-conversion-node-arm 4 | DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION) 5 | DOCKER_IMAGE_TAGNAME_ARM=$(DOCKER_IMAGE_NAME_ARM):$(DOCKER_IMAGE_VERSION) 6 | 7 | default: build 8 | 9 | build: 10 | docker build -t $(DOCKER_IMAGE_TAGNAME) . 11 | docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest 12 | 13 | push:build 14 | docker push $(DOCKER_IMAGE_TAGNAME) 15 | docker push $(DOCKER_IMAGE_NAME) 16 | 17 | ## Same cmds for arm 18 | build-arm: 19 | docker build -t $(DOCKER_IMAGE_TAGNAME_ARM) -f Dockerfile-arm . 20 | docker tag $(DOCKER_IMAGE_TAGNAME_ARM) $(DOCKER_IMAGE_NAME_ARM):latest 21 | push-arm:build-arm 22 | docker push $(DOCKER_IMAGE_TAGNAME_ARM) 23 | docker push $(DOCKER_IMAGE_NAME_ARM) -------------------------------------------------------------------------------- /JSON-Generator/example.json: -------------------------------------------------------------------------------- 1 | { 2 | id: '', 3 | tag: 'tag_v6fSJ1v2sD', 4 | groupid: 'groupid_nX8CCRqUtB', 5 | sequencenumber: 4, 6 | sequencetotal: 5, 7 | priority: 9, 8 | version: 4, 9 | timestamp: 0, 10 | publisher: 'LKCdqQ4cFFfYCDtjQCvzQY', 11 | authid: 'authid_UNpRHsVAnY', 12 | authgroup: 'authgroup_i2CQOrPUvr', 13 | chainposition: 9, 14 | hash: 'hash_POJZftQBmb', 15 | previoushash: 'previoushash_uQl7V10KP4', 16 | nonce: 'nonce_045Nv1VXBz', 17 | difficultytarget: 7, 18 | infotype: 'infotype/gen', 19 | infoformat: 'infoformat/gen', 20 | contextdata: 'contextdata_UKCb3peBZEzRFmGHPcUFybDZzTJoNg', 21 | contentdata: '{"coord":{"lon":"57.5071","lat":"78.5196"},"weather":[{"id":8,"main":"main_wv3Ic72r3S","description":"description_EMDzhTPBUe"}],"main":{"temp":"221.8861","pressure":10,"humidity":10,"temp_min":"225.5203","temp_max":"80.9565"},"visibility":10,"wind":{"speed":"108.6960","deg":"83.8040"},"id":4,"name":"NAME_8gMkkts2Ac"}' 22 | } 23 | 24 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | # Notices for Eclipse ioFog 2 | 3 | This content is produced and maintained by the Eclipse ioFog project. 4 | 5 | * Project home: https://projects.eclipse.org/projects/iot.iofog 6 | 7 | ## Trademarks 8 | 9 | Eclipse ioFog is a trademark of the Eclipse Foundation. 10 | 11 | ## Copyright 12 | 13 | All content is the property of the respective authors or their employers. For 14 | more information regarding authorship of content, please consult the listed 15 | source code repository logs. 16 | 17 | ## Declared Project Licenses 18 | 19 | This program and the accompanying materials are made available under the terms 20 | of the Eclipse Public License v. 2.0 which is available at 21 | http://www.eclipse.org/legal/epl-2.0. 22 | 23 | SPDX-License-Identifier: EPL-2.0 24 | 25 | ## Source Code 26 | 27 | The project maintains the following source code repositories: 28 | 29 | * https://github.com/ioFog 30 | * http://git.eclipse.org/c/iofog/org.eclipse.iofog.git 31 | 32 | ## Third-party Content 33 | 34 | ## Cryptography 35 | 36 | Content may contain encryption software. The country in which you are currently 37 | may have restrictions on the import, possession, and use, and/or re-export to 38 | another country, of encryption software. BEFORE using any encryption software, 39 | please check the country's laws, regulations and policies concerning the import, 40 | possession, or use, and re-export of encryption software, to see if this is 41 | permitted. 42 | 43 | -------------------------------------------------------------------------------- /sensors-data/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs' 2 | import * as parse from 'csv-parse' 3 | import * as path from 'path' 4 | 5 | import * as ioFogClient from '@iofog/nodejs-sdk' 6 | 7 | let time = 69000 8 | debugger 9 | 10 | function read(client): Promise { 11 | return new Promise((resolve, reject) => { 12 | const parser = parse({ 13 | delimiter: ',' 14 | }) 15 | 16 | parser.on('readable', async () => { 17 | let data = parser.read() 18 | while (data) { 19 | const ms = (data[0] * 1000) - time 20 | await sleep(ms) 21 | 22 | time = (data[0] * 1000) 23 | const json = { 24 | time: Date.now(), 25 | speed: data[1] * 2.23694, 26 | acceleration: data[4], 27 | rpm: data[5], 28 | } 29 | 30 | const ioMessage = client.ioMessage() 31 | ioMessage.contentdata = Buffer.from(JSON.stringify(json)).toString('base64') 32 | ioMessage.infotype = 'application/json' 33 | ioMessage.infoformat = 'text/utf-8' 34 | client.sendNewMessage(ioMessage, { 35 | onMessageReceipt: () => { }, 36 | onBadRequest: (error) => { console.log('Error sending message', error) }, 37 | onError: (error) => { console.log('Error sending message', error) }, 38 | }) 39 | 40 | data = parser.read() 41 | } 42 | }).on('end', () => resolve()) 43 | 44 | fs.createReadStream(path.resolve(__dirname, '../data/trip-data.csv')) 45 | .pipe(parser) 46 | }) 47 | } 48 | 49 | function sleep(ms: number): Promise { 50 | return new Promise((resolve) => { 51 | setTimeout(() => { 52 | resolve() 53 | }, ms) 54 | }) 55 | } 56 | 57 | ioFogClient.init('iofog', 54321, null, async () => { 58 | while (true) { 59 | await read(ioFogClient) 60 | } 61 | }) 62 | -------------------------------------------------------------------------------- /freeboard/dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "allow_edit": true, 4 | "plugins": [], 5 | "panes": [ 6 | { 7 | "width": 1, 8 | "row": { 9 | "3": 1, 10 | "4": 1 11 | }, 12 | "col": { 13 | "3": -8, 14 | "4": -8 15 | }, 16 | "col_width": 1, 17 | "widgets": [ 18 | { 19 | "type": "gauge", 20 | "settings": { 21 | "title": "Speed", 22 | "value": "(datasources[\"Sensors\"][\"speed\"] * 1).toFixed(1)", 23 | "units": "mph", 24 | "min_value": 0, 25 | "max_value": "100" 26 | } 27 | }, 28 | { 29 | "type": "gauge", 30 | "settings": { 31 | "title": "RPM", 32 | "value": "Math.trunc(datasources[\"Sensors\"][\"rpm\"])", 33 | "units": "rpm", 34 | "min_value": 0, 35 | "max_value": "5000" 36 | } 37 | }, 38 | { 39 | "type": "gauge", 40 | "settings": { 41 | "title": "Acceleration", 42 | "value": "(datasources[\"Sensors\"][\"acceleration\"] * 1).toFixed(3)", 43 | "units": "m/s^2", 44 | "min_value": 0, 45 | "max_value": "5" 46 | } 47 | } 48 | ] 49 | }, 50 | { 51 | "width": 1, 52 | "row": { 53 | "3": 1, 54 | "4": 1 55 | }, 56 | "col": { 57 | "3": 2, 58 | "4": 3 59 | }, 60 | "col_width": 2, 61 | "widgets": [ 62 | { 63 | "type": "sparkline", 64 | "settings": { 65 | "title": "Acceleration", 66 | "value": [ 67 | "datasources[\"Sensors\"][\"acceleration\"]" 68 | ] 69 | } 70 | }, 71 | { 72 | "type": "text_widget", 73 | "settings": { 74 | "title": "Time", 75 | "size": "regular", 76 | "value": "new Date(datasources[\"Sensors\"][\"time\"]).toISOString()", 77 | "animate": true 78 | } 79 | } 80 | ] 81 | } 82 | ], 83 | "datasources": [ 84 | { 85 | "name": "Sensors", 86 | "type": "JSON", 87 | "settings": { 88 | "url": "http://localhost:10101", 89 | "use_thingproxy": false, 90 | "refresh": 1, 91 | "method": "GET" 92 | } 93 | } 94 | ], 95 | "columns": 4 96 | } -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | # Contributing to Eclipse ioFog 2 | 3 | Thanks for your interest in this project. 4 | 5 | ## Project description 6 | 7 | The Eclipse ioFog set of technologies is a fog computing layer that can be 8 | installed on any hardware running Linux. Once installed, it provides a universal 9 | runtime for microservices to run on the edge. In addition to a common runtime, 10 | ioFog also provides a set of useful services including a message bus, dynamic 11 | configuration of the microservices, and remote debugging. 12 | 13 | * https://projects.eclipse.org/projects/iot.iofog 14 | 15 | ## Developer resources 16 | 17 | Information regarding source code management, builds, coding standards, and 18 | more. 19 | 20 | * https://projects.eclipse.org/projects/iot.iofog/developer 21 | 22 | The project maintains the following source code repositories 23 | 24 | * https://github.com/ioFog 25 | * http://git.eclipse.org/c/iofog/org.eclipse.iofog.git 26 | 27 | This project uses Bugzilla to track ongoing development and issues. 28 | 29 | * Search for issues: https://eclipse.org/bugs/buglist.cgi?product=IoFog 30 | * Create a new report: https://eclipse.org/bugs/enter_bug.cgi?product=IoFog 31 | 32 | Be sure to search for existing bugs before you create another one. Remember that 33 | contributions are always welcome! 34 | 35 | ## Eclipse Contributor Agreement 36 | 37 | Before your contribution can be accepted by the project team contributors must 38 | electronically sign the Eclipse Contributor Agreement (ECA). 39 | 40 | * http://www.eclipse.org/legal/ECA.php 41 | 42 | Commits that are provided by non-committers must have a Signed-off-by field in 43 | the footer indicating that the author is aware of the terms by which the 44 | contribution has been provided to the project. The non-committer must 45 | additionally have an Eclipse Foundation account and must have a signed Eclipse 46 | Contributor Agreement (ECA) on file. 47 | 48 | For more information, please see the Eclipse Committer Handbook: 49 | https://www.eclipse.org/projects/handbook/#resources-commit 50 | 51 | ## Contact 52 | 53 | Contact the project developers via the project's "dev" list. 54 | 55 | * https://dev.eclipse.org/mailman/listinfo/iofog-dev 56 | -------------------------------------------------------------------------------- /json-rest-api-cors-enabled/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ******************************************************************************* 3 | * Copyright (c) 2018 Edgeworx, Inc. 4 | * 5 | * This program and the accompanying materials are made available under the 6 | * terms of the Eclipse Public License v. 2.0 which is available at 7 | * http://www.eclipse.org/legal/epl-2.0 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 10 | * ******************************************************************************* 11 | */ 12 | 13 | const http = require('http') 14 | const ioFogClient = require('@iofog/nodejs-sdk') 15 | 16 | const PORT = 80 17 | 18 | let lastMessage = {} 19 | 20 | ioFogClient.init('iofog', 54321, null, () => { 21 | ioFogClient.wsControlConnection( 22 | { 23 | 'onNewConfigSignal': () => { }, 24 | 'onError': (error) => { 25 | console.error('There was an error with Control WebSocket connection to ioFog: ', error) 26 | }, 27 | } 28 | ) 29 | 30 | ioFogClient.wsMessageConnection(() => { }, { 31 | 'onMessages': (messages) => { 32 | if (messages && messages.length) { 33 | lastMessage = messages[0] 34 | } 35 | }, 36 | 'onMessageReceipt': (messageId, timestamp) => { }, 37 | 'onError': (error) => { 38 | console.error('There was an error with Message WebSocket connection to ioFog: ', error) 39 | } 40 | }) 41 | }) 42 | 43 | 44 | const server = http.createServer((request, response) => { 45 | switch (request.method) { 46 | case 'OPTIONS': { 47 | response.writeHead(200, { 48 | 'Access-Control-Allow-Credentials' : true, 49 | 'Access-Control-Allow-Origin': '*', 50 | 'Access-Control-Allow-Methods': 'GET, OPTIONS', 51 | 'Access-Control-Allow-Headers':'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With', 52 | }) 53 | response.end() 54 | break 55 | } 56 | case 'GET': { 57 | let data = '{}' 58 | if (lastMessage && lastMessage.contentdata) { 59 | const base64 = lastMessage.contentdata 60 | data = (new Buffer(base64, 'base64')).toString('utf8') 61 | } 62 | response.writeHead(200, { 63 | 'Content-Type': 'application/json', 64 | 'Access-Control-Allow-Origin': '*', 65 | }) 66 | response.end(data) 67 | break 68 | } 69 | } 70 | }) 71 | 72 | server.listen(PORT, () => { }) 73 | -------------------------------------------------------------------------------- /JSON-Subselect/java_version/src/org/eclipse/iofog/IOFogAPIListenerImpl.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (c) 2018 Edgeworx, Inc. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0 7 | * 8 | * SPDX-License-Identifier: EPL-2.0 9 | ********************************************************************************/ 10 | 11 | package org.eclipse.iofog; 12 | 13 | import org.eclipse.iofog.api.listener.IOFogAPIListener; 14 | import org.eclipse.iofog.elements.IOMessage; 15 | 16 | import javax.json.JsonObject; 17 | import java.util.List; 18 | 19 | public class IOFogAPIListenerImpl implements IOFogAPIListener { 20 | 21 | private final JSONSubselectMain mainLogInstance; 22 | 23 | public IOFogAPIListenerImpl(JSONSubselectMain mainLogInstance) { 24 | this.mainLogInstance = mainLogInstance; 25 | } 26 | 27 | @Override 28 | public void onMessages(List list) { 29 | //System.out.println("IOFogAPIListenerImpl.onMessages"); 30 | list.forEach(message -> mainLogInstance.buildAndSendMessage(message)); 31 | } 32 | 33 | @Override 34 | public void onMessagesQuery(long l, long l1, List list) { 35 | //System.out.println("IOFogAPIListenerImpl.onMessagesQuery"); 36 | /* do nothing */ 37 | } 38 | 39 | @Override 40 | public void onError(Throwable throwable) { 41 | //System.out.println("IOFogAPIListenerImpl.onError"); 42 | System.err.println("Error:" + throwable); 43 | } 44 | 45 | @Override 46 | public void onBadRequest(String s) { 47 | //System.out.println("IOFogAPIListenerImpl.onBadRequest"); 48 | System.err.println("Bad Request: " + s); 49 | } 50 | 51 | @Override 52 | public void onMessageReceipt(String s, long l) { 53 | //System.out.println("IOFogAPIListenerImpl.onMessageReceipt"); 54 | /* do nothing */ 55 | } 56 | 57 | @Override 58 | public void onNewConfig(JsonObject jsonObject) { 59 | //System.out.println("IOFogAPIListenerImpl.onNewConfig"); 60 | mainLogInstance.setConfig(jsonObject); 61 | } 62 | 63 | @Override 64 | public void onNewConfigSignal() { 65 | //System.out.println("IOFogAPIListenerImpl.onNewConfigSignal"); 66 | mainLogInstance.updateConfig(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /temperature_sensor_simulator/index.py: -------------------------------------------------------------------------------- 1 | #******************************************************************************** 2 | # Copyright (c) 2018 Edgeworx, Inc. 3 | # 4 | # This program and the accompanying materials are made available under the 5 | # terms of the Eclipse Public License v. 2.0 which is available at 6 | # http://www.eclipse.org/legal/epl-2.0 7 | # 8 | # SPDX-License-Identifier: EPL-2.0 9 | #******************************************************************************** 10 | 11 | import json 12 | import random 13 | import threading 14 | import time 15 | from iofog_python_sdk.client import IoFogClient, IoFogException 16 | from iofog_python_sdk.iomessage import IoMessage 17 | from iofog_python_sdk.listener import * 18 | 19 | current_config = None 20 | client = IoFogClient() 21 | lock = threading.Lock() 22 | MINIMUM_VALUE = 'minimumvalue' 23 | MAXIMUM_VALUE = 'maximumvalue' 24 | TEMPERATURE = 'temperature' 25 | DECIMAL_CELSIUS = 'decimal/celsius' 26 | FREQUENCY = 'frequency' 27 | DEFAULT_SLEEP_TIME = 2000 28 | DEFAULT_MINIMUM_VALUE = 0. 29 | DEFAULT_MAXIMUM_VALUE = 100. 30 | 31 | 32 | def update_config(): 33 | attempt_limit = 5 34 | config = None 35 | 36 | while attempt_limit > 0: 37 | try: 38 | config = client.get_config() 39 | break 40 | except IoFogException, ex: 41 | attempt_limit -= 1 42 | print str(ex) 43 | 44 | if attempt_limit == 0: 45 | print 'Config update failed :(' 46 | return 47 | 48 | lock.acquire() 49 | global current_config 50 | current_config = config 51 | lock.release() 52 | 53 | 54 | def simulate_temperature(): 55 | lock.acquire() 56 | config = current_config 57 | lock.release() 58 | 59 | if not config: 60 | print 'Config is empty...' 61 | return False 62 | 63 | time.sleep(config.get(FREQUENCY, DEFAULT_SLEEP_TIME) / 1000.) 64 | msg = IoMessage() 65 | msg.infotype = TEMPERATURE 66 | msg.infoformat = DECIMAL_CELSIUS 67 | contentdata = json.dumps(random.uniform(config.get(MINIMUM_VALUE, DEFAULT_MINIMUM_VALUE), 68 | config.get(MAXIMUM_VALUE, DEFAULT_MAXIMUM_VALUE))) 69 | msg.contentdata = bytearray(contentdata) 70 | client.post_message_via_socket(msg) 71 | 72 | 73 | class ControlListener(IoFogControlWsListener): 74 | def on_control_signal(self): 75 | update_config() 76 | 77 | 78 | class MessageListener(IoFogMessageWsListener): 79 | def on_receipt(self, message_id, timestamp): 80 | print 'Receipt: {} {}'.format(message_id, timestamp) 81 | 82 | 83 | update_config() 84 | client.establish_message_ws_connection(MessageListener()) 85 | client.establish_control_ws_connection(ControlListener()) 86 | 87 | while True: 88 | simulate_temperature() 89 | -------------------------------------------------------------------------------- /humidity_sensor_simulator/index.py: -------------------------------------------------------------------------------- 1 | #******************************************************************************** 2 | # Copyright (c) 2018 Edgeworx, Inc. 3 | # 4 | # This program and the accompanying materials are made available under the 5 | # terms of the Eclipse Public License v. 2.0 which is available at 6 | # http://www.eclipse.org/legal/epl-2.0 7 | # 8 | # SPDX-License-Identifier: EPL-2.0 9 | #******************************************************************************** 10 | 11 | import json 12 | import random 13 | import threading 14 | 15 | import time 16 | from iofog_python_sdk.client import IoFogClient, IoFogException 17 | from iofog_python_sdk.iomessage import IoMessage 18 | from iofog_python_sdk.listener import * 19 | 20 | current_config = None 21 | client = IoFogClient() 22 | lock = threading.Lock() 23 | MINIMUM_VALUE = 'minimumvalue' 24 | MAXIMUM_VALUE = 'maximumvalue' 25 | HUMIDITY_RELATIVE = 'humidity/relative' 26 | DECIMAL_PERCENT = 'decimal/percent' 27 | FREQUENCY = 'frequency' 28 | DEFAULT_SLEEP_TIME = 2000 29 | DEFAULT_MINIMUM_VALUE = 0. 30 | DEFAULT_MAXIMUM_VALUE = 100. 31 | 32 | 33 | def update_config(): 34 | attempt_limit = 5 35 | config = None 36 | 37 | while attempt_limit > 0: 38 | try: 39 | config = client.get_config() 40 | break 41 | except IoFogException, ex: 42 | attempt_limit -= 1 43 | print str(ex) 44 | 45 | if attempt_limit == 0: 46 | print 'Config update failed :(' 47 | return 48 | 49 | lock.acquire() 50 | global current_config 51 | current_config = config 52 | lock.release() 53 | 54 | 55 | def simulate_humidity(): 56 | lock.acquire() 57 | config = current_config 58 | lock.release() 59 | 60 | if not config: 61 | print 'Config is empty...' 62 | return False 63 | 64 | time.sleep(config.get(FREQUENCY, DEFAULT_SLEEP_TIME) / 1000.) 65 | msg = IoMessage() 66 | msg.infotype = HUMIDITY_RELATIVE 67 | msg.infoformat = DECIMAL_PERCENT 68 | contentdata = json.dumps(random.uniform(config.get(MINIMUM_VALUE, DEFAULT_MINIMUM_VALUE), 69 | config.get(MAXIMUM_VALUE, DEFAULT_MAXIMUM_VALUE))) 70 | msg.contentdata = bytearray(contentdata) 71 | client.post_message_via_socket(msg) 72 | 73 | 74 | class ControlListener(IoFogControlWsListener): 75 | def on_control_signal(self): 76 | update_config() 77 | 78 | 79 | class MessageListener(IoFogMessageWsListener): 80 | def on_receipt(self, message_id, timestamp): 81 | print 'Receipt: {} {}'.format(message_id, timestamp) 82 | 83 | 84 | update_config() 85 | client.establish_message_ws_connection(MessageListener()) 86 | client.establish_control_ws_connection(ControlListener()) 87 | 88 | while True: 89 | simulate_humidity() 90 | -------------------------------------------------------------------------------- /diagnostics/README.md: -------------------------------------------------------------------------------- 1 | ## Diagnostics Container 2 | **Diagnostics Container** is a container that performs diagnostics of basic functionality to work with ioFog.
3 | Use the Diagnostic Container if something goes wrong on your machine with ioFog Agent, e.g. a container cannot connect to ioFog host, ioFog client is not created, RestBlue not available, and so on.
With the detailed report that the Diagnostics Container creates, you can be aware of the issues that may arise.
4 |
5 | ### Diagnostics Container performs the following checks: 6 | - Client creation (tries to create ioFog client that checks if all the required parameters are provided);
7 | - Tries to update config (tries to get ioFog config, ping report_url provided from config);
8 | - Sends HEARTBEAT “signal” to report_url (every 30 sec if not specified);
9 | - Tries to connect to Sockets (Control and Message Websockets);
10 | - Checks if RestBlue is available (connects to RestBlue System Container);
11 | 12 | ### Examples of configuration JSONs: 13 | The full config for the container should look the following way:
14 | ```{ "report_url": { "ip": "127.0.0.1", "host" : "localhost", "port" : 6666, "url" : "/report", "secure" : false }, {"ping_rb": true, "interval" : 60}```
15 | If "report_url" is not provided or is not available then whole output will be logged to console. Following example is valid and can be used if you don't need to send logs outside:
16 | ```{"ping_rb": true, "interval" : 60}```
17 | 18 | ### Config explanation:
19 | "report_url": config specifying where to send logs (log to console; not required parameter)
20 | "ip": ip of machine for log reporting (used when host is unreachable)
21 | "host" : host of machine for log reporting
22 | "port" : port of listening server that is ready for log receiving (if not specified, assumed to be 80)
23 | "url" : relative url where to send config
24 | "secure" : set this parameter to "true" if you want to use https protocol (if not specified, assumed to be "false" and uses http)
25 | "ping_rb" : connect to RestBlue System Container if true is set
26 | "interval" : perform checks after the specified interval; every 30 sec if not specified
27 | 28 | ### Launching the Container 29 | Use [iofogctl](https://github.com/eclipse-iofog/iofogctl) a CLI tool for installation, configuration, and operation of ioFog Edge Compute Networks (ECNs). 30 | **! catalog-id = 4 for Diagnostics container.**
31 | 32 | ### Diagnostics output is the detailed logs about system functionality. 33 | 1. Go to Terminal. 34 | 2. Get the list of containers with the following command: sudo docker ps in order to use container name for obtaining logs. 35 | 3. See the detailed logs about system functionality with the following command: sudo docker logs CONTAINER_NAME (the last value is Container Name taken from the output of sudo docker ps). 36 | 37 | ![DIAGNOSTICS](https://github.com/ioFog/example-microservices/blob/master/diagnostics/DIAGNOSTICS.png) 38 | -------------------------------------------------------------------------------- /JSON-Subselect/java_version/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 17 | 4.0.0 18 | 19 | org.eclipse.iofog 20 | json_subselect 21 | 0.1 22 | jar 23 | 24 | JSON Sub-select Container 25 | Container takes the portions of a JSON message that they want and publish the results as a new message 26 | with whatever ioMessage format they want. 27 | https://github.com/ioFog/example-microservices.git 28 | 29 | 30 | 31 | Eclipse Public License 2.0 32 | https://www.eclipse.org/legal/epl-2.0/ 33 | repo 34 | 35 | 36 | 37 | 38 | 39 | org.eclipse.iofog 40 | iofog-java-sdk 41 | 0.0.1 42 | system 43 | ${basedir}/iofog-java-sdk-0.0.1.jar 44 | 45 | 46 | 47 | 48 | src 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-compiler-plugin 53 | 3.3 54 | 55 | 1.8 56 | 1.8 57 | 58 | 59 | 60 | org.apache.maven.plugins 61 | maven-assembly-plugin 62 | 63 | false 64 | 65 | 66 | org.eclipse.iofog.JSONSubselectMain 67 | 68 | 69 | 70 | jar-with-dependencies 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Go template 3 | # Binaries for programs and plugins 4 | *.exe 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, build with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 16 | .glide/ 17 | ### Node template 18 | # Logs 19 | logs 20 | *.log 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # Runtime data 26 | pids 27 | *.pid 28 | *.seed 29 | *.pid.lock 30 | 31 | # Directory for instrumented libs generated by jscoverage/JSCover 32 | lib-cov 33 | 34 | # Coverage directory used by tools like istanbul 35 | coverage 36 | 37 | # nyc test coverage 38 | .nyc_output 39 | 40 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 41 | .grunt 42 | 43 | # Bower dependency directory (https://bower.io/) 44 | bower_components 45 | 46 | # node-waf configuration 47 | .lock-wscript 48 | 49 | # Compiled binary addons (http://nodejs.org/api/addons.html) 50 | build/Release 51 | 52 | # Dependency directories 53 | node_modules/ 54 | jspm_packages/ 55 | .vscode 56 | package-lock.json 57 | 58 | # Typescript v1 declaration files 59 | typings/ 60 | 61 | # Optional npm cache directory 62 | .npm 63 | 64 | # Optional eslint cache 65 | .eslintcache 66 | 67 | # Optional REPL history 68 | .node_repl_history 69 | 70 | # Output of 'npm pack' 71 | *.tgz 72 | 73 | # Yarn Integrity file 74 | .yarn-integrity 75 | 76 | # dotenv environment variables file 77 | .env 78 | 79 | ### Python template 80 | # Byte-compiled / optimized / DLL files 81 | __pycache__/ 82 | *.py[cod] 83 | *$py.class 84 | 85 | # C extensions 86 | *.so 87 | 88 | # Distribution / packaging 89 | .Python 90 | env/ 91 | build/ 92 | develop-eggs/ 93 | dist/ 94 | downloads/ 95 | eggs/ 96 | .eggs/ 97 | lib/ 98 | lib64/ 99 | parts/ 100 | sdist/ 101 | var/ 102 | wheels/ 103 | *.egg-info/ 104 | .installed.cfg 105 | *.egg 106 | 107 | # PyInstaller 108 | # Usually these files are written by a python script from a template 109 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 110 | *.manifest 111 | *.spec 112 | 113 | # Installer logs 114 | pip-log.txt 115 | pip-delete-this-directory.txt 116 | 117 | # Unit test / coverage reports 118 | htmlcov/ 119 | .tox/ 120 | .coverage 121 | .coverage.* 122 | .cache 123 | nosetests.xml 124 | coverage.xml 125 | *,cover 126 | .hypothesis/ 127 | 128 | # Translations 129 | *.mo 130 | *.pot 131 | 132 | # Django stuff: 133 | *.log 134 | local_settings.py 135 | 136 | # Flask stuff: 137 | instance/ 138 | .webassets-cache 139 | 140 | # Scrapy stuff: 141 | .scrapy 142 | 143 | # Sphinx documentation 144 | docs/_build/ 145 | 146 | # PyBuilder 147 | target/ 148 | 149 | # Jupyter Notebook 150 | .ipynb_checkpoints 151 | 152 | # pyenv 153 | .python-version 154 | 155 | # celery beat schedule file 156 | celerybeat-schedule 157 | 158 | # SageMath parsed files 159 | *.sage.py 160 | 161 | # dotenv 162 | .env 163 | 164 | # virtualenv 165 | .venv 166 | venv/ 167 | ENV/ 168 | 169 | # Spyder project settings 170 | .spyderproject 171 | 172 | # Rope project settings 173 | .ropeproject 174 | 175 | /.idea/ 176 | -------------------------------------------------------------------------------- /seismic_sensor_simulator/index.py: -------------------------------------------------------------------------------- 1 | #******************************************************************************** 2 | # Copyright (c) 2018 Edgeworx, Inc. 3 | # 4 | # This program and the accompanying materials are made available under the 5 | # terms of the Eclipse Public License v. 2.0 which is available at 6 | # http://www.eclipse.org/legal/epl-2.0 7 | # 8 | # SPDX-License-Identifier: EPL-2.0 9 | #******************************************************************************** 10 | 11 | import json 12 | import random 13 | import threading 14 | 15 | import time 16 | from iofog_python_sdk.client import IoFogClient, IoFogException 17 | from iofog_python_sdk.iomessage import IoMessage 18 | from iofog_python_sdk.listener import * 19 | 20 | current_config = None 21 | client = IoFogClient() 22 | lock = threading.Lock() 23 | MINIMUM_VALUE_X = 'minimumvalueaxisx' 24 | MAXIMUM_VALUE_X = 'maximumvalueaxisx' 25 | MINIMUM_VALUE_Y = 'minimumvalueaxisy' 26 | MAXIMUM_VALUE_Y = 'maximumvalueaxisy' 27 | MINIMUM_VALUE_Z = 'minimumvalueaxisz' 28 | MAXIMUM_VALUE_Z = 'maximumvalueaxisz' 29 | MOTION_X = 'motionx' 30 | MOTION_Y = 'motiony' 31 | MOTION_Z = 'motionz' 32 | SEISMIC_JSON = 'seismic/json' 33 | TEXT_UTF8 = 'text/utf8' 34 | FREQUENCY = 'frequency' 35 | DEFAULT_SLEEP_TIME = 2000 36 | DEFAULT_MINIMUM_VALUE = 0. 37 | DEFAULT_MAXIMUM_VALUE = 100. 38 | 39 | 40 | def update_config(): 41 | attempt_limit = 5 42 | config = None 43 | 44 | while attempt_limit > 0: 45 | try: 46 | config = client.get_config() 47 | break 48 | except IoFogException, ex: 49 | attempt_limit -= 1 50 | print str(ex) 51 | 52 | if attempt_limit == 0: 53 | print 'Config update failed :(' 54 | return 55 | 56 | lock.acquire() 57 | global current_config 58 | current_config = config 59 | lock.release() 60 | 61 | 62 | def simulate_seismic(): 63 | lock.acquire() 64 | config = current_config 65 | lock.release() 66 | 67 | if not config: 68 | print 'Config is empty...' 69 | return False 70 | 71 | time.sleep(config.get(FREQUENCY, DEFAULT_SLEEP_TIME) / 1000.) 72 | msg = IoMessage() 73 | msg.infotype = SEISMIC_JSON 74 | msg.infoformat = TEXT_UTF8 75 | contentdata = { 76 | MOTION_X: random.uniform(config.get(MINIMUM_VALUE_X, DEFAULT_MINIMUM_VALUE), 77 | config.get(MAXIMUM_VALUE_X, DEFAULT_MAXIMUM_VALUE)), 78 | MOTION_Y: random.uniform(config.get(MINIMUM_VALUE_Y, DEFAULT_MINIMUM_VALUE), 79 | config.get(MAXIMUM_VALUE_Y, DEFAULT_MAXIMUM_VALUE)), 80 | MOTION_Z: random.uniform(config.get(MINIMUM_VALUE_Z, DEFAULT_MINIMUM_VALUE), 81 | config.get(MAXIMUM_VALUE_Z, DEFAULT_MAXIMUM_VALUE)) 82 | } 83 | contentdata = json.dumps(contentdata) 84 | msg.contentdata = bytearray(contentdata) 85 | client.post_message_via_socket(msg) 86 | 87 | 88 | class ControlListener(IoFogControlWsListener): 89 | def on_control_signal(self): 90 | update_config() 91 | 92 | 93 | class MessageListener(IoFogMessageWsListener): 94 | def on_receipt(self, message_id, timestamp): 95 | print 'Receipt: {} {}'.format(message_id, timestamp) 96 | 97 | 98 | update_config() 99 | client.establish_message_ws_connection(MessageListener()) 100 | client.establish_control_ws_connection(ControlListener()) 101 | 102 | while True: 103 | simulate_seismic() 104 | -------------------------------------------------------------------------------- /JSON-Subselect/python_version/main.py: -------------------------------------------------------------------------------- 1 | #******************************************************************************** 2 | # Copyright (c) 2018 Edgeworx, Inc. 3 | # 4 | # This program and the accompanying materials are made available under the 5 | # terms of the Eclipse Public License v. 2.0 which is available at 6 | # http://www.eclipse.org/legal/epl-2.0 7 | # 8 | # SPDX-License-Identifier: EPL-2.0 9 | #******************************************************************************** 10 | 11 | import json 12 | import threading 13 | 14 | from iofog_python_sdk.client import IoFogClient 15 | from iofog_python_sdk.exception import IoFogException 16 | from iofog_python_sdk.iomessage import IoMessage 17 | from iofog_python_sdk.listener import * 18 | from jsonpath_rw import parse 19 | 20 | client = IoFogClient() 21 | current_config = None 22 | SELECTIONS = 'selections' 23 | INPUT_TYPE = 'inputtype' 24 | INPUT_FORMAT = 'inputformat' 25 | OUTPUT_TYPE = 'outputtype' 26 | OUTPUT_FORMAT = 'outputformat' 27 | OUTPUTS = 'outputs' 28 | SUBSELECTION = 'subselection' 29 | FIELD_NAME = 'fieldname' 30 | OUTPUT_ARRAY = 'outputjsonarray' 31 | lock = threading.Lock() 32 | 33 | 34 | def update_config(): 35 | attempt_limit = 5 36 | config = None 37 | 38 | while attempt_limit > 0: 39 | try: 40 | config = client.get_config() 41 | break 42 | except IoFogException, ex: 43 | attempt_limit -= 1 44 | print str(ex) 45 | 46 | if attempt_limit == 0: 47 | print 'Config update failed :(' 48 | return 49 | 50 | lock.acquire() 51 | global current_config 52 | current_config = config 53 | lock.release() 54 | 55 | 56 | def transform_content_data(content_data, outputs): 57 | content_data_json = json.loads(str(content_data)) 58 | new_content_data = {} 59 | for output in outputs: 60 | match = parse(output.get(SUBSELECTION, '')).find(content_data_json) 61 | if match: 62 | new_content_data[output[FIELD_NAME]] = match[0].value 63 | else: 64 | new_content_data[output[FIELD_NAME]] = None 65 | 66 | if output.get(OUTPUT_ARRAY, False): 67 | new_content_data[output[FIELD_NAME]] = [new_content_data[output[FIELD_NAME]]] 68 | 69 | return json.dumps(new_content_data) 70 | 71 | 72 | def transform_message(msg): 73 | lock.acquire() 74 | config = current_config 75 | lock.release() 76 | 77 | if not config: 78 | print 'Config is empty...' 79 | return None 80 | 81 | new_msg = None 82 | for selection in config.get(SELECTIONS, []): 83 | if msg.infotype == selection.get(INPUT_TYPE) and msg.infoformat == selection.get(INPUT_FORMAT): 84 | content_data = transform_content_data(msg.contentdata, selection.get(OUTPUTS, [])) 85 | new_msg = IoMessage() 86 | new_msg.infotype = str(selection.get(OUTPUT_TYPE, '')) 87 | new_msg.infoformat = str(selection.get(OUTPUT_FORMAT, '')) 88 | new_msg.contentdata = bytearray(content_data) 89 | 90 | return new_msg 91 | 92 | 93 | def on_message_routine(io_msg): 94 | new_msg = transform_message(io_msg) 95 | if new_msg: 96 | client.post_message_via_socket(new_msg) 97 | else: 98 | print 'Message did not pass transformation' 99 | 100 | 101 | class MyControlListener(IoFogControlWsListener): 102 | def on_control_signal(self): 103 | update_config() 104 | 105 | 106 | class MyMessageListener(IoFogMessageWsListener): 107 | def on_receipt(self, message_id, timestamp): 108 | print 'Receipt: {} {}'.format(message_id, timestamp) 109 | 110 | def on_message(self, io_msg): 111 | on_message_routine(io_msg) 112 | # threading.Thread(target=on_message_routine, args=(io_msg,)).start() 113 | 114 | 115 | update_config() 116 | client.establish_message_ws_connection(MyMessageListener()) 117 | client.establish_control_ws_connection(MyControlListener()) 118 | -------------------------------------------------------------------------------- /JSON-Subselect/go_version/subselect.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (c) 2018 Edgeworx, Inc. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0 7 | * 8 | * SPDX-License-Identifier: EPL-2.0 9 | ********************************************************************************/ 10 | 11 | package main 12 | 13 | import ( 14 | "encoding/json" 15 | "errors" 16 | "fmt" 17 | sdk "github.com/ioFog/iofog-go-sdk" 18 | "log" 19 | "os" 20 | "strconv" 21 | "strings" 22 | "sync" 23 | ) 24 | 25 | var ( 26 | logger = log.New(os.Stderr, "", log.LstdFlags) 27 | containerConfig map[string]interface{} 28 | configMutex = sync.RWMutex{} 29 | client, clientError = sdk.NewDefaultIoFogClient() 30 | ) 31 | 32 | type Config struct { 33 | Selections []Selection `json:"selections"` 34 | } 35 | 36 | type Selection struct { 37 | InputType string `json:"inputtype"` 38 | InputFormat string `json:"inputformat"` 39 | OutputType string `json:"outputtype"` 40 | OutputFormat string `json:"outputformat"` 41 | Outputs []Output `json:"outputs"` 42 | } 43 | 44 | type Output struct { 45 | SubSelection string `json:"subselection"` 46 | OutputJSONArray bool `json:"outputjsonarray"` 47 | FieldName string `json:"fieldname"` 48 | } 49 | 50 | func main() { 51 | if clientError != nil { 52 | logger.Println(clientError.Error()) 53 | return 54 | } 55 | 56 | updateConfig() 57 | 58 | go func() { 59 | confChannel := client.EstablishControlWsConnection(0) 60 | for { 61 | select { 62 | case <-confChannel: 63 | updateConfig() 64 | } 65 | } 66 | }() 67 | 68 | messageChannel, receiptChannel := client.EstablishMessageWsConnection(0, 0) 69 | for { 70 | select { 71 | case msg := <-messageChannel: 72 | 73 | go func() { 74 | selected, err := buildMessage(msg.(*sdk.IoMessage)) 75 | if err != nil { 76 | logger.Println(err.Error()) 77 | } else { 78 | client.SendMessageViaSocket(selected) 79 | } 80 | }() 81 | case <-receiptChannel: 82 | 83 | } 84 | } 85 | 86 | } 87 | 88 | func updateConfig() { 89 | attemptLimit := 5 90 | var config map[string]interface{} 91 | var err error 92 | 93 | for config, err = client.GetConfig(); err != nil && attemptLimit > 0; attemptLimit-- { 94 | logger.Println(err.Error()) 95 | } 96 | 97 | if attemptLimit == 0 { 98 | logger.Println("Update config failed") 99 | return 100 | } 101 | 102 | configMutex.Lock() 103 | containerConfig = config 104 | configMutex.Unlock() 105 | } 106 | 107 | func buildMessage(msg *sdk.IoMessage) (*sdk.IoMessage, error) { 108 | var newMsg *sdk.IoMessage = nil 109 | config := new(Config) 110 | configMutex.RLock() 111 | configBytes, err := json.Marshal(containerConfig) 112 | configMutex.RUnlock() 113 | 114 | if err != nil { 115 | return nil, err 116 | } else if err = json.Unmarshal(configBytes, config); err != nil { 117 | return nil, err 118 | } 119 | 120 | for _, selection := range config.Selections { 121 | if msg.InfoType == selection.InputType && msg.InfoFormat == selection.InputFormat { 122 | newContentData, err := transformContentData(msg.ContentData, selection.Outputs) 123 | if err != nil { 124 | return nil, err 125 | } 126 | newMsg = &sdk.IoMessage{ 127 | InfoType: selection.OutputType, 128 | InfoFormat: selection.OutputFormat, 129 | ContentData: newContentData, 130 | } 131 | } 132 | } 133 | 134 | if newMsg == nil { 135 | return nil, errors.New("No matched selections for input message found") 136 | } 137 | return newMsg, nil 138 | } 139 | 140 | func transformContentData(contentData []byte, outputs []Output) (result []byte, e error) { 141 | oldJsonContentData := make(map[string]interface{}) 142 | newJsonContentData := make(map[string]interface{}) 143 | var curValue interface{} 144 | var present bool 145 | err := json.Unmarshal(contentData, &oldJsonContentData) 146 | if err != nil { 147 | return nil, err 148 | } 149 | defer func() { 150 | if r := recover(); r != nil { 151 | e = errors.New(fmt.Sprintf("Panic while subselecting occurred: %v", r)) 152 | } 153 | }() 154 | for _, output := range outputs { 155 | path := strings.Split(output.SubSelection, ".") 156 | curValue = oldJsonContentData 157 | for _, p := range path { 158 | if curValueAsMap, ok := curValue.(map[string]interface{}); ok { 159 | if curValue, present = curValueAsMap[p]; !present { 160 | curValue = nil 161 | break 162 | } 163 | } else if curValueAsArray, ok := curValue.([]interface{}); ok { 164 | indx, err := strconv.ParseInt(p, 10, 0) 165 | if err != nil { 166 | return nil, err 167 | } 168 | curValue = curValueAsArray[indx] 169 | } 170 | } 171 | if output.OutputJSONArray { 172 | newJsonContentData[output.FieldName] = []interface{}{curValue} 173 | } else { 174 | newJsonContentData[output.FieldName] = curValue 175 | } 176 | } 177 | return json.Marshal(newJsonContentData) 178 | } 179 | -------------------------------------------------------------------------------- /Temperature-Conversion/index.py: -------------------------------------------------------------------------------- 1 | #******************************************************************************** 2 | # Copyright (c) 2018 Edgeworx, Inc. 3 | # 4 | # This program and the accompanying materials are made available under the 5 | # terms of the Eclipse Public License v. 2.0 which is available at 6 | # http://www.eclipse.org/legal/epl-2.0 7 | # 8 | # SPDX-License-Identifier: EPL-2.0 9 | #******************************************************************************** 10 | 11 | import json 12 | import threading 13 | 14 | from iofog_python_sdk.client import IoFogClient, IoFogException 15 | from iofog_python_sdk.listener import * 16 | from jsonpath_rw import parse 17 | 18 | current_config = None 19 | client = IoFogClient() 20 | lock = threading.Lock() 21 | DECIMAL_KELVIN = 'decimal/kelvin' 22 | DECIMAL_CELSIUS = 'decimal/celsius' 23 | DECIMAL_FAHRENHEIT = 'decimal/fahrenheit' 24 | FAHRENHEIT = 'fahrenheit' 25 | CELSIUS = 'celsius' 26 | KELVIN = 'kelvin' 27 | TEMPERATURE = 'temperature' 28 | OUTPUT_FORMAT = 'outputformat' 29 | FIELD_NAME = 'fieldname' 30 | 31 | convert_map = { 32 | DECIMAL_KELVIN: { 33 | KELVIN: lambda x: x, 34 | CELSIUS: lambda x: x - 273.15, 35 | FAHRENHEIT: lambda x: (x * (9. / 5)) - 459.67 36 | }, 37 | DECIMAL_CELSIUS: { 38 | KELVIN: lambda x: x + 273.15, 39 | CELSIUS: lambda x: x, 40 | FAHRENHEIT: lambda x: (x * x * (9. / 5)) + 32 41 | }, 42 | DECIMAL_FAHRENHEIT: { 43 | KELVIN: lambda x: (x + 459.67) * (5. / 9), 44 | CELSIUS: lambda x: (x - 32) * (5. / 9), 45 | FAHRENHEIT: lambda x: x 46 | } 47 | } 48 | 49 | 50 | def get_path(match): 51 | if match.context is not None: 52 | for path_element in get_path(match.context): 53 | yield path_element 54 | yield str(match.path) 55 | 56 | 57 | def update_json(json_obj, path, value): 58 | try: 59 | first = next(path) 60 | # check if item is an array 61 | if first.startswith('[') and first.endswith(']'): 62 | try: 63 | first = int(first[1:-1]) 64 | except ValueError: 65 | pass 66 | json_obj[first] = update_json(json_obj[first], path, value) 67 | return json_obj 68 | except StopIteration: 69 | return value 70 | 71 | 72 | def convert(cur_format, new_format, content_data, field_name): 73 | content_data_loaded = json.loads(str(content_data)) 74 | if isinstance(content_data_loaded, float) or isinstance(content_data_loaded, int): 75 | new_value = convert_map[cur_format][new_format](content_data_loaded) 76 | new_content_data = json.dumps(new_value) 77 | else: 78 | pattern = parse(field_name) 79 | match = pattern.find(content_data_loaded) 80 | if match: 81 | cur_value = match[0].value 82 | new_value = convert_map[cur_format][new_format](cur_value) 83 | new_content_data = update_json(content_data_loaded, get_path(match[0]), new_value) 84 | new_content_data = json.dumps(new_content_data) 85 | else: 86 | raise Exception('No match found') 87 | 88 | return new_content_data 89 | 90 | 91 | def build_message(msg_old): 92 | lock.acquire() 93 | config = current_config 94 | lock.release() 95 | 96 | if not config: 97 | print 'Config is empty...' 98 | return None 99 | 100 | try: 101 | if msg_old.infoformat in [DECIMAL_KELVIN, DECIMAL_CELSIUS, DECIMAL_FAHRENHEIT] \ 102 | and msg_old.infotype == TEMPERATURE: 103 | if OUTPUT_FORMAT in config: 104 | content_data = convert(msg_old.infoformat, config[OUTPUT_FORMAT], 105 | msg_old.contentdata, config.get(FIELD_NAME)) 106 | msg_old.contentdata = bytearray(content_data) 107 | msg_old.infoformat = str('decimal/' + config[OUTPUT_FORMAT]) 108 | return msg_old 109 | except Exception as exc: 110 | print 'Error building msg: ' + str(exc) 111 | 112 | return None 113 | 114 | 115 | def update_config(): 116 | attempt_limit = 5 117 | config = None 118 | 119 | while attempt_limit > 0: 120 | try: 121 | config = client.get_config() 122 | break 123 | except IoFogException, ex: 124 | attempt_limit -= 1 125 | print str(ex) 126 | 127 | if attempt_limit == 0: 128 | print 'Config update failed :(' 129 | return 130 | 131 | lock.acquire() 132 | global current_config 133 | current_config = config 134 | lock.release() 135 | 136 | 137 | class ControlListener(IoFogControlWsListener): 138 | def on_control_signal(self): 139 | update_config() 140 | 141 | 142 | class MessageListener(IoFogMessageWsListener): 143 | def on_receipt(self, message_id, timestamp): 144 | print 'Receipt: {} {}'.format(message_id, timestamp) 145 | 146 | def on_message(self, io_msg): 147 | new_msg = build_message(io_msg) 148 | if new_msg: 149 | client.post_message_via_socket(new_msg) 150 | else: 151 | print 'Message did not pass transformation' 152 | 153 | 154 | update_config() 155 | client.establish_message_ws_connection(MessageListener()) 156 | client.establish_control_ws_connection(ControlListener()) 157 | -------------------------------------------------------------------------------- /Temperature-Conversion/nodejs_version/tempConversion.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ******************************************************************************* 3 | * Copyright (c) 2018 Edgeworx, Inc. 4 | * 5 | * This program and the accompanying materials are made available under the 6 | * terms of the Eclipse Public License v. 2.0 which is available at 7 | * http://www.eclipse.org/legal/epl-2.0 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 10 | * ******************************************************************************* 11 | */ 12 | 13 | var ioFogClient = require('@iofog/nodejs-sdk'); 14 | 15 | var currentConfig; 16 | 17 | ioFogClient.init('iofog', 54321, null, 18 | function tempConversionMain() { 19 | // first thing first is to get config from ioFog 20 | fetchConfig(); 21 | ioFogClient.wsControlConnection( 22 | { 23 | 'onNewConfigSignal': 24 | function onNewConfigSignal() { 25 | // upon receiving signal about new config available -> go get it 26 | fetchConfig(); 27 | }, 28 | 'onError': 29 | function onControlSocketError(error) { 30 | console.error('There was an error with Control WebSocket connection to ioFog: ', error); 31 | } 32 | } 33 | ); 34 | ioFogClient.wsMessageConnection( 35 | function(ioFogClient) { /* don't need to do anything on opened Message Socket */ }, 36 | { 37 | 'onMessages': 38 | function onMessagesSocket(messages) { 39 | if(messages) { 40 | // when getting new messages we store newest and delete oldest corresponding to configured limit 41 | for (var i = 0; i < messages.length; i++) { 42 | var new_msg = buildMessage(messages[i]); 43 | if(new_msg) { 44 | ioFogClient.wsSendMessage(new_msg); 45 | } else { 46 | console.info('Message didn\'t pass transformation. Nothing to send.'); 47 | } 48 | } 49 | } 50 | }, 51 | 'onMessageReceipt': 52 | function(messageId, timestamp) { /*console.log('message Receipt');*/ }, 53 | 'onError': 54 | function onMessageSocketError(error) { 55 | console.error('There was an error with Message WebSocket connection to ioFog: ', error); 56 | } 57 | } 58 | ); 59 | } 60 | ); 61 | 62 | function fetchConfig() { 63 | ioFogClient.getConfig( 64 | { 65 | 'onBadRequest': 66 | function onConfigBadRequest(errorMsg) { 67 | console.error('There was an error in request for getting config from the local API: ', errorMsg); 68 | }, 69 | 'onNewConfig': 70 | function onConfig(config) { 71 | try { 72 | if(config) { 73 | if (JSON.stringify(config) !== JSON.stringify(currentConfig)) { 74 | currentConfig = config; 75 | } 76 | } 77 | } catch (error) { 78 | console.error('Couldn\'t stringify Config JSON: ', error); 79 | } 80 | }, 81 | 'onError': 82 | function onConfigError(error) { 83 | console.error('There was an error getting config from the local API: ', error); 84 | } 85 | } 86 | ); 87 | } 88 | 89 | function buildMessage(oldMsg) { 90 | var newMsg = null; 91 | if ((oldMsg.infoformat == "decimal/kelvin" || oldMsg.infoformat == "decimal/celsius" || 92 | oldMsg.infoformat == "decimal/fahrenheit") && oldMsg.infotype == "temperature") { 93 | var format = oldMsg.infoformat.split("/")[1]; 94 | if (currentConfig && currentConfig.outputformat && format != currentConfig.outputformat){ 95 | newMsg = ioFogClient.ioMessage(); 96 | newMsg.contentdata = convert(oldMsg.infoformat, currentConfig.outputformat, oldMsg.contentdata); 97 | newMsg.infoformat = "decimal/" + currentConfig.outputformat; 98 | } 99 | } 100 | return newMsg; 101 | } 102 | 103 | function convert(currentFormat, outputFormat, data) { 104 | try { 105 | var json = JSON.parse(data.toString()); 106 | var value = json[Object.keys(json)[0]]; 107 | if (currentFormat == 'decimal/kelvin' && outputFormat == 'fahrenheit') { 108 | value = (value * (9 / 5)) - 459.67; 109 | } else if (currentFormat == 'decimal/kelvin' && outputFormat == 'celsius' ) { 110 | value = value - 273.15; 111 | } else if (currentFormat == 'decimal/fahrenheit' && outputFormat == 'kelvin' ) { 112 | value = (value + 459.67) * (5 / 9); 113 | } else if (currentFormat == 'decimal/fahrenheit' && outputFormat == 'celsius') { 114 | value = (value - 32) * (5 / 9); 115 | } else if (currentFormat == 'decimal/celsius' && outputFormat == 'kelvin') { 116 | value = value + 273.15; 117 | } else if (currentFormat == 'decimal/celsius' && outputFormat == 'fahrenheit') { 118 | value = (value * (9 / 5)) + 32; 119 | } else { 120 | value = 0; 121 | } 122 | var buf = Buffer(32); 123 | buf.writeDoubleBE(value, 0); 124 | return buf; 125 | } catch (error) { 126 | console.error('Error converting temperature: ', error); 127 | return 'FAILED_TEMPERATURE_CONVERSION'; 128 | } 129 | } -------------------------------------------------------------------------------- /JSON-Generator/jsonGenerator.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ******************************************************************************* 3 | * Copyright (c) 2018 Edgeworx, Inc. 4 | * 5 | * This program and the accompanying materials are made available under the 6 | * terms of the Eclipse Public License v. 2.0 which is available at 7 | * http://www.eclipse.org/legal/epl-2.0 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 10 | * ******************************************************************************* 11 | */ 12 | 13 | var ioFogClient = require('@iofog/nodejs-sdk'); 14 | 15 | var frequency = 1000; 16 | var currentConfig; 17 | var sendIntervalFunction; 18 | 19 | ioFogClient.init('iofog', 54321, null, 20 | function jsonGeneratorMain() { 21 | // first thing first is to get config from ioFog 22 | fetchConfig(); 23 | ioFogClient.wsControlConnection( 24 | { 25 | 'onNewConfigSignal': 26 | function onNewConfigSignal() { 27 | // upon receiving signal about new config available -> go get it 28 | fetchConfig(); 29 | }, 30 | 'onError': 31 | function onControlSocketError(error) { 32 | console.error('There was an error with Control WebSocket connection to ioFog: ', error); 33 | } 34 | } 35 | ); 36 | ioFogClient.wsMessageConnection( 37 | function(ioFogClient) { /* don't need to do anything on opened Message Socket */ }, 38 | { 39 | 'onMessages': 40 | function onMessagesSocket(messages) { /* don't need to do anything on opened Message Socket */ }, 41 | 'onMessageReceipt': 42 | function(messageId, timestamp) { /*console.log('message Receipt');*/ }, 43 | 'onError': 44 | function onMessageSocketError(error) { 45 | console.error('There was an error with Message WebSocket connection to ioFog: ', error); 46 | } 47 | } 48 | ); 49 | } 50 | ); 51 | 52 | function fetchConfig() { 53 | ioFogClient.getConfig( 54 | { 55 | 'onBadRequest': 56 | function onConfigBadRequest(errorMsg) { 57 | console.error('There was an error in request for getting config from the local API: ', errorMsg); 58 | }, 59 | 'onNewConfig': 60 | function onConfig(config) { 61 | try { 62 | if(config) { 63 | if (JSON.stringify(config) !== JSON.stringify(currentConfig)) { 64 | currentConfig = config; 65 | clearInterval(sendIntervalFunction); 66 | if (config.frequency && config.frequency > 1000) { 67 | frequency = config.frequency; 68 | } 69 | sendGeneratedMessage(); 70 | } 71 | } 72 | } catch (error) { 73 | console.error('Couldn\'t stringify Config JSON: ', error); 74 | } 75 | }, 76 | 'onError': 77 | function onConfigError(error) { 78 | console.error('There was an error getting config from the local API: ', error); 79 | } 80 | } 81 | ); 82 | } 83 | 84 | function sendGeneratedMessage() { 85 | sendIntervalFunction = setInterval( 86 | function sendMessage() { 87 | var jsonContentData = buildComplexJSON(); 88 | var ioMessage = ioFogClient.ioMessage({ 89 | 'tag': generateString('tag'), 90 | 'groupid': generateString('groupid'), 91 | 'sequencenumber': generateNumber(), 92 | 'sequencetotal': generateNumber(), 93 | 'priority': generateNumber(), 94 | 'authid': generateString('authid'), 95 | 'authgroup': generateString('authgroup'), 96 | 'chainposition': generateNumber(), 97 | 'hash': generateString('hash'), 98 | 'previoushash': generateString('previoushash'), 99 | 'nonce': generateString('nonce'), 100 | 'difficultytarget': generateNumber(), 101 | 'infotype': 'infotype/gen', 102 | 'infoformat': 'infoformat/gen', 103 | 'contextdata': generateString('contextdata', 30), 104 | 'contentdata' : jsonContentData 105 | }); 106 | ioFogClient.wsSendMessage(ioMessage); 107 | }, frequency); 108 | } 109 | 110 | function buildComplexJSON() { 111 | var new_json = { 112 | coord : { 113 | lon : generateFloat(true), 114 | lat : generateFloat(true) 115 | }, 116 | weather :[{ 117 | id : generateNumber(), 118 | main : generateString('main'), 119 | description : generateString('description') 120 | }], 121 | main : { 122 | temp : generateFloat(), 123 | pressure : generateNumber(), 124 | humidity : generateNumber(), 125 | temp_min : generateFloat(), 126 | temp_max : generateFloat() 127 | }, 128 | visibility : generateNumber(), 129 | wind : { 130 | speed : generateFloat(), 131 | deg : generateFloat() 132 | }, 133 | id : generateNumber(), 134 | name : generateString('NAME') 135 | }; 136 | return JSON.stringify(new_json); 137 | } 138 | 139 | function generateString(rootString, length) { 140 | const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 141 | 142 | var result = ''; 143 | if(!length) { 144 | length = 10; 145 | } 146 | for (var i = 0; i < length; i++) { 147 | result += ALPHABET.charAt(Math.floor(Math.random() * ALPHABET.length)); 148 | } 149 | if (rootString) { 150 | result = rootString + '_' + result; 151 | } 152 | return result; 153 | } 154 | 155 | function generateNumber() { 156 | return Math.floor(Math.random() * (10) + 1); 157 | } 158 | 159 | function generateFloat(negative) { 160 | if(negative) { 161 | return (Math.random() * (100.0000 + 100.000) - 100.000).toFixed(4); 162 | } 163 | return (Math.random() * (300.0000)).toFixed(4); 164 | } -------------------------------------------------------------------------------- /JSON-Subselect/nodejs_version/jsonSubselect.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ******************************************************************************* 3 | * Copyright (c) 2018 Edgeworx, Inc. 4 | * 5 | * This program and the accompanying materials are made available under the 6 | * terms of the Eclipse Public License v. 2.0 which is available at 7 | * http://www.eclipse.org/legal/epl-2.0 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 10 | * ******************************************************************************* 11 | */ 12 | 13 | var ioFogClient = require('@iofog/nodejs-sdk'); 14 | 15 | var currentConfig; 16 | 17 | ioFogClient.init('iofog', 54321, null, 18 | function jsonSubselectMain() { 19 | // first thing first is to get config from ioFog 20 | fetchConfig(); 21 | ioFogClient.wsControlConnection( 22 | { 23 | 'onNewConfigSignal': 24 | function onNewConfigSignal() { 25 | // upon receiving signal about new config available -> go get it 26 | fetchConfig(); 27 | }, 28 | 'onError': 29 | function onControlSocketError(error) { 30 | console.error('There was an error with Control WebSocket connection to ioFog: ', error); 31 | } 32 | } 33 | ); 34 | ioFogClient.wsMessageConnection( 35 | function(ioFogClient) { /* don't need to do anything on opened Message Socket */ }, 36 | { 37 | 'onMessages': 38 | function onMessagesSocket(messages) { 39 | if(messages) { 40 | // when getting new messages we store newest and delete oldest corresponding to configured limit 41 | for (var i = 0; i < messages.length; i++) { 42 | var new_msg = buildMessage(messages[i]); 43 | if(new_msg) { 44 | ioFogClient.wsSendMessage(new_msg); 45 | } else { 46 | console.info('Message didn\'t pass transformation. Nothing to send.'); 47 | } 48 | } 49 | } 50 | }, 51 | 'onMessageReceipt': 52 | function(messageId, timestamp) { /*console.log('message Receipt');*/ }, 53 | 'onError': 54 | function onMessageSocketError(error) { 55 | console.error('There was an error with Message WebSocket connection to ioFog: ', error); 56 | } 57 | } 58 | ); 59 | } 60 | ); 61 | 62 | function fetchConfig() { 63 | ioFogClient.getConfig( 64 | { 65 | 'onBadRequest': 66 | function onConfigBadRequest(errorMsg) { 67 | console.error('There was an error in request for getting config from the local API: ', errorMsg); 68 | }, 69 | 'onNewConfig': 70 | function onConfig(config) { 71 | try { 72 | if(config) { 73 | if (JSON.stringify(config) !== JSON.stringify(currentConfig)) { 74 | currentConfig = config; 75 | } 76 | } 77 | } catch (error) { 78 | console.error('Couldn\'t stringify Config JSON: ', error); 79 | } 80 | }, 81 | 'onError': 82 | function onConfigError(error) { 83 | console.error('There was an error getting config from the local API: ', error); 84 | } 85 | } 86 | ); 87 | } 88 | 89 | function buildMessage(oldMsg) { 90 | var newMsg = null; 91 | if (currentConfig && currentConfig.selections) { 92 | var selections = currentConfig.selections; 93 | for(var index = 0; index < selections.length; index++) { 94 | var subSelectionConfig = selections[index]; 95 | if(oldMsg.infotype === subSelectionConfig.inputtype && oldMsg.infoformat === subSelectionConfig.inputformat) { 96 | newMsg = ioFogClient.ioMessage(); 97 | newMsg.contentdata = buildJson(oldMsg.contentdata, subSelectionConfig); 98 | newMsg.infotype = subSelectionConfig.outputtype; 99 | newMsg.infoformat = subSelectionConfig.outputformat; 100 | } 101 | } 102 | } 103 | return newMsg; 104 | } 105 | 106 | function buildJson(contentdata, subSelectionConfig) { 107 | var new_json = {}; 108 | try { 109 | var contentdataJson = JSON.parse(contentdata.toString()); 110 | if (subSelectionConfig.outputs) { 111 | var outputs = subSelectionConfig.outputs; 112 | for(var i=0; i < outputs.length; i++) { 113 | var outputConfig = outputs[i]; 114 | var subselection, subselections, value = null; 115 | if (outputConfig.subselection) { 116 | subselection = outputConfig.subselection; 117 | subselections = subselection.split('.'); 118 | } 119 | if (subselection in contentdataJson) { 120 | value = contentdataJson[subselection]; 121 | } else if (subselections.length > 1) { 122 | var sub_json = contentdataJson; 123 | for (var index=0; index < subselections.length; index++) { 124 | if (subselections[index] in sub_json) { 125 | sub_json = sub_json[subselections[index]]; 126 | continue; 127 | } 128 | } 129 | if(JSON.stringify(sub_json) != JSON.stringify(contentdataJson)) { 130 | value = sub_json; 131 | } 132 | } 133 | if (outputConfig.fieldname) { 134 | new_json[outputConfig.fieldname] = getOutputValue(value, outputConfig); 135 | } else { 136 | new_json[subselection] = getOutputValue(value, outputConfig); 137 | } 138 | } 139 | } 140 | } catch (error) { 141 | console.error('Error building new json message:', error); 142 | } 143 | return JSON.stringify(new_json); 144 | } 145 | 146 | function getOutputValue(value, config){ 147 | var output_value; 148 | if (config.outputjsonarray) { 149 | if (value) { 150 | if (value instanceof Array) { 151 | output_value = value; 152 | } else { 153 | output_value = [value]; 154 | } 155 | } else { 156 | output_value = []; 157 | } 158 | } else { 159 | output_value = value; 160 | } 161 | return output_value; 162 | } -------------------------------------------------------------------------------- /OpenWeatherMap/openWeatherMap.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ******************************************************************************* 3 | * Copyright (c) 2018 Edgeworx, Inc. 4 | * 5 | * This program and the accompanying materials are made available under the 6 | * terms of the Eclipse Public License v. 2.0 which is available at 7 | * http://www.eclipse.org/legal/epl-2.0 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 10 | * ******************************************************************************* 11 | */ 12 | 13 | var request = require('request'); 14 | var ioFogClient = require('@iofog/nodejs-sdk'); 15 | 16 | var frequency = 1000; 17 | var timeout = 10000; 18 | var httpRequestsLimit = 3; 19 | var openHttpRequestsCounter = 0; 20 | var currentConfig; 21 | var openWeatherIntervalFunction; 22 | 23 | ioFogClient.init('iofog', 54321, null, 24 | function openWeatherMapMain(){ 25 | // first thing first is to get config from ioFog 26 | fetchConfig(); 27 | ioFogClient.wsControlConnection( 28 | { 29 | 'onNewConfigSignal': 30 | function onNewConfigSignal() { 31 | // upon receiving signal about new config available -> go get it 32 | fetchConfig(); 33 | }, 34 | 'onError': 35 | function onControlSocketError(error) { 36 | console.error('There was an error with WebSocket connection to ioFog: ', error); 37 | } 38 | } 39 | ); 40 | } 41 | ); 42 | 43 | function fetchConfig() { 44 | ioFogClient.getConfig( 45 | { 46 | 'onBadRequest': 47 | function onConfigBadRequest(errorMsg) { 48 | console.error('There was an error in request for getting config from the local API: ', errorMsg); 49 | }, 50 | 'onNewConfig': 51 | function onNewConfig(config) { 52 | try { 53 | if(config) { 54 | if (JSON.stringify(config) !== JSON.stringify(currentConfig)) { 55 | currentConfig = config; 56 | clearInterval(openWeatherIntervalFunction); 57 | if (config.frequency && config.frequency > 1000) { 58 | frequency = config.frequency; 59 | } 60 | getOWMdata(); 61 | } 62 | } 63 | } catch (error) { 64 | console.error('Couldn\'t stringify Config JSON: ', error); 65 | } 66 | }, 67 | 'onError': 68 | function onConfigError(error) { 69 | console.error('There was an error getting config from the local API: ', error); 70 | } 71 | } 72 | ); 73 | } 74 | 75 | function getOWMdata() { 76 | openWeatherIntervalFunction = setInterval( 77 | function getAndPostMessage() { 78 | if (currentConfig && currentConfig.citycode && currentConfig.apikey) { 79 | var url = 'http://api.openweathermap.org/data/2.5/weather?id=' + currentConfig.citycode + '&APPID=' + currentConfig.apikey; 80 | if (openHttpRequestsCounter <= httpRequestsLimit) { 81 | openHttpRequestsCounter++; 82 | request( 83 | { 84 | uri: url, 85 | method: 'GET', 86 | timeout: timeout 87 | }, 88 | function handleOWMResponse(error, response, body) { 89 | openHttpRequestsCounter--; 90 | if (!error && response.statusCode === 200) { 91 | var weatherResponse = body; 92 | 93 | var ioMsg = ioFogClient.ioMessage( 94 | { 95 | 'tag': '', 96 | 'groupid': '', 97 | 'sequencenumber': 1, 98 | 'sequencetotal': 1, 99 | 'priority': 0, 100 | 'authid': '', 101 | 'authgroup': '', 102 | 'chainposition': 0, 103 | 'hash': '', 104 | 'previoushash': '', 105 | 'nonce': '', 106 | 'difficultytarget': 0, 107 | 'infotype': 'weather/mixed/open-weather-map', 108 | 'infoformat': 'text/json', 109 | 'contextdata': Buffer(0), 110 | 'contentdata': Buffer(weatherResponse) 111 | } 112 | ); 113 | 114 | ioFogClient.sendNewMessage( 115 | ioMsg, 116 | { 117 | 'onBadRequest': function onSendMsgBadRequest(errorMsg) { 118 | console.error('There was an error in request for posting new message to the local API: ', errorMsg); 119 | }, 120 | 'onMessageReceipt': function onMessageReceipt(messageId, timestamp) { 121 | /*console.log('Message was posted successfully: ID = ' + messageId + ' and time ' + new Date(timestamp));*/ 122 | }, 123 | 'onError': function onSendMsgError(error) { 124 | console.error('There was an error posting OpenWeatherMap new message to local API: ', error); 125 | } 126 | } 127 | ); 128 | } else { 129 | if (error) { 130 | console.error('Got an error requesting data from OpenWeatherMap : ', error); 131 | } 132 | if (response) { 133 | console.error('Response status code from OpenWeatherMap : ', response.statusCode); 134 | } 135 | } 136 | } 137 | ); 138 | } else { 139 | console.warn('Sorry, the limit of open HTTP requests is exceeded.'); 140 | } 141 | } 142 | }, frequency); 143 | } -------------------------------------------------------------------------------- /JSON-REST-API/jsonRestApi.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ******************************************************************************* 3 | * Copyright (c) 2018 Edgeworx, Inc. 4 | * 5 | * This program and the accompanying materials are made available under the 6 | * terms of the Eclipse Public License v. 2.0 which is available at 7 | * http://www.eclipse.org/legal/epl-2.0 8 | * 9 | * SPDX-License-Identifier: EPL-2.0 10 | * ******************************************************************************* 11 | */ 12 | 13 | var http = require('http'); 14 | var ioFogClient = require('@iofog/nodejs-sdk'); 15 | 16 | const PARSING_ERROR_MSG = 'ENCODING FAILED'; 17 | const PORT = 80; 18 | var messageLimit = 1; 19 | var msgsBuffer = []; 20 | var currentConfig; 21 | 22 | ioFogClient.init('iofog', 54321, null, 23 | function jsonRestApiMain() { 24 | // first thing first is to get config from ioFog 25 | fetchConfig(); 26 | ioFogClient.wsControlConnection( 27 | { 28 | 'onNewConfigSignal': 29 | function onNewConfigSignal() { 30 | // upon receiving signal about new config available -> go get it 31 | fetchConfig(); 32 | }, 33 | 'onError': 34 | function onControlSocketError(error) { 35 | console.error('There was an error with Control WebSocket connection to ioFog: ', error); 36 | } 37 | } 38 | ); 39 | ioFogClient.wsMessageConnection( 40 | function(ioFogClient) { /* don't need to do anything on opened Message Socket */ }, 41 | { 42 | 'onMessages': 43 | function onMessagesSocket(messages) { 44 | if(messages) { 45 | // when getting new messages we store newest and delete oldest corresponding to configured limit 46 | for (var i = 0; i < messages.length; i++) { 47 | if (msgsBuffer.length > (messageLimit - 1)) { 48 | msgsBuffer.splice(0, (msgsBuffer.length - (messageLimit - 1))); 49 | } 50 | msgsBuffer.push(messages[i]); 51 | } 52 | } 53 | }, 54 | 'onMessageReceipt': 55 | function(messageId, timestamp) { /* we received the receipt for posted msg */ }, 56 | 'onError': 57 | function onMessageSocketError(error) { 58 | console.error('There was an error with Message WebSocket connection to ioFog: ', error); 59 | } 60 | } 61 | ); 62 | } 63 | ); 64 | 65 | 66 | var server = http.createServer( 67 | function handleRequest(request, response) { 68 | var responseMsgs = []; 69 | if (currentConfig) { 70 | /** 71 | Checking if config contains not empty accesstoken then messages can be reached only by url with token: 72 | http://containerIPaddress/token/{accesstoken} otherwise it's forbidden access (403). 73 | **/ 74 | if (currentConfig.accesstoken && currentConfig.accesstoken.length !== 0) { 75 | var url = request.url.split('/'); 76 | if (url.length !== 3 || 77 | (url.length === 3 && url[1] === 'token' && url[2] !== currentConfig.accesstoken)) { 78 | response.writeHead(403, {'Content-Type': 'application/json'}); 79 | response.end(); 80 | return; 81 | } 82 | } 83 | if (currentConfig.outputfields && Object.keys(currentConfig.outputfields).length) { 84 | var ioMsgProps = Object.keys(currentConfig.outputfields); 85 | for (var i = 0; i < msgsBuffer.length; i++) { 86 | var responseMsg = Object.create({}); 87 | for (var j = 0; j < ioMsgProps.length; j++) { 88 | var outputPropName = currentConfig.outputfields[ioMsgProps[j]]; 89 | var outputPropValue = msgsBuffer[i][ioMsgProps[j]]; 90 | if(ioMsgProps[j] === 'contentdata') { 91 | outputPropValue = parsePropertyValue(outputPropValue, currentConfig.contentdataencoding); 92 | } else if(ioMsgProps[j] === 'contextdata') { 93 | outputPropValue = parsePropertyValue(outputPropValue, currentConfig.contextdataencoding); 94 | } 95 | responseMsg[outputPropName] = outputPropValue; 96 | } 97 | responseMsgs.push(responseMsg); 98 | } 99 | } else { 100 | responseMsgs = msgsBuffer; 101 | } 102 | } 103 | response.writeHead(200, {'Content-Type':'application/json'}); 104 | response.end(JSON.stringify(responseMsgs)); 105 | } 106 | ); 107 | 108 | server.listen(PORT, function openPort() { 109 | //console.info('JSON REST API Container listening on port: ', PORT); 110 | }); 111 | 112 | function fetchConfig() { 113 | ioFogClient.getConfig( 114 | { 115 | 'onBadRequest': 116 | function onConfigBadRequest(errorMsg) { 117 | console.error('There was an error in request for getting config from the local API: ', errorMsg); 118 | }, 119 | 'onNewConfig': 120 | function onConfig(config) { 121 | try { 122 | if(config) { 123 | if (JSON.stringify(config) !== JSON.stringify(currentConfig)) { 124 | currentConfig = config; 125 | if(currentConfig.buffersize) { 126 | messageLimit = currentConfig.buffersize; 127 | } else { 128 | messageLimit = 1; 129 | } 130 | if (msgsBuffer.length > messageLimit) { 131 | msgsBuffer.splice(0, (msgsBuffer.length - messageLimit)); 132 | } 133 | } 134 | } 135 | } catch (error) { 136 | console.error('Couldn\'t stringify Config JSON: ', error); 137 | } 138 | }, 139 | 'onError': 140 | function onConfigError(error) { 141 | console.error('There was an error getting config from the local API: ', error); 142 | } 143 | } 144 | ); 145 | } 146 | 147 | function parsePropertyValue(propValue, dataEncoding) { 148 | var stringFormats = ['base64', 'utf8', 'ascii']; 149 | var integerFormat = 'integer', decimalFormat = 'decimal'; 150 | var booleanFormat = 'boolean'; 151 | try { 152 | if(propValue) { 153 | if (dataEncoding) { 154 | if (stringFormats.indexOf(dataEncoding) > -1) { 155 | return propValue.toString(dataEncoding); 156 | } 157 | if (integerFormat === dataEncoding) { 158 | return propValue.readUIntBE(0, propValue.length); 159 | } 160 | if (decimalFormat === dataEncoding && propValue.length >= 8) { 161 | return propValue.readDoubleBE(); 162 | } 163 | if (booleanFormat === dataEncoding) { 164 | if (propValue[0] === 0) { 165 | return false; 166 | } else { 167 | return true; 168 | } 169 | } 170 | console.warn(PARSING_ERROR_MSG + ' : Sorry, we don\'t support \'' + dataEncoding + 171 | '\' this format. Please choose among next formats: ' + stringFormats + 172 | ', ' + integerFormat + ', ' + decimalFormat + ', ' + booleanFormat); 173 | return PARSING_ERROR_MSG; 174 | } else { 175 | return propValue.toString('base64'); 176 | } 177 | } else { 178 | return ''; 179 | } 180 | } catch (err) { 181 | console.warn(PARSING_ERROR_MSG + ': ', err); 182 | return PARSING_ERROR_MSG; 183 | } 184 | } -------------------------------------------------------------------------------- /JSON-Subselect/java_version/src/org/eclipse/iofog/JSONSubselectMain.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (c) 2018 Edgeworx, Inc. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0 7 | * 8 | * SPDX-License-Identifier: EPL-2.0 9 | ********************************************************************************/ 10 | 11 | package org.eclipse.iofog; 12 | 13 | import org.eclipse.iofog.api.IOFogClient; 14 | import org.eclipse.iofog.elements.IOMessage; 15 | import io.netty.util.internal.StringUtil; 16 | 17 | import javax.json.*; 18 | import java.io.StringReader; 19 | 20 | /** 21 | * Main class 22 | */ 23 | public class JSONSubselectMain { 24 | 25 | private static Object fetchConfigLock = new Object(); 26 | private static JsonObject config = null; 27 | private static String containerId = ""; 28 | 29 | private static IOFogClient ioFogClient; 30 | private static IOFogAPIListenerImpl listener; 31 | 32 | public static void main(String[] args) throws Exception { 33 | 34 | JSONSubselectMain instance = new JSONSubselectMain(); 35 | 36 | if (args.length > 0 && args[0].startsWith("--id=")) { 37 | containerId = args[0].substring(args[0].indexOf('=') + 1); 38 | } else { 39 | containerId = System.getenv("SELFNAME"); 40 | } 41 | 42 | if (StringUtil.isNullOrEmpty(containerId)) { 43 | System.err.println("Container Id is not specified. Please, use --id=XXXX parameter or set the id as SELFNAME=XXXX environment property"); 44 | } else { 45 | String ioFogHost = System.getProperty("iofog_host", "iofog"); 46 | int ioFogPort = 54321; 47 | try { 48 | ioFogPort = Integer.parseInt(System.getProperty("iofog_port", "54321")); 49 | } catch (Exception e) { 50 | /* default value 54321 will be used */ 51 | } 52 | 53 | ioFogClient = new IOFogClient(ioFogHost, ioFogPort, containerId); 54 | listener = new IOFogAPIListenerImpl(instance); 55 | 56 | updateConfig(); 57 | 58 | try { 59 | ioFogClient.openControlWebSocket(listener); 60 | } catch (Exception e) { 61 | System.err.println("Unable to open Control WebSocket to ioFog: " + e.getMessage()); 62 | } 63 | 64 | try { 65 | ioFogClient.openMessageWebSocket(listener); 66 | } catch (Exception e) { 67 | System.err.println("Unable to open Message WebSocket to ioFog: " + e.getMessage()); 68 | } 69 | } 70 | } 71 | 72 | public void setConfig(JsonObject configObject) { 73 | config = configObject; 74 | synchronized (fetchConfigLock) { 75 | fetchConfigLock.notifyAll(); 76 | } 77 | } 78 | 79 | public static void updateConfig(){ 80 | config = null; 81 | try { 82 | while (config == null) { 83 | ioFogClient.fetchContainerConfig(listener); 84 | synchronized (fetchConfigLock) { 85 | fetchConfigLock.wait(1000); 86 | } 87 | } 88 | } catch (Exception e) { 89 | System.err.println("Error fetching config: " + e.getMessage()); 90 | } 91 | } 92 | 93 | public static void buildAndSendMessage(IOMessage ioMessage) { 94 | IOMessage tMessage = buildMessage(ioMessage); 95 | if(tMessage != null) { 96 | ioFogClient.sendMessageToWebSocket(tMessage); 97 | } else { 98 | System.out.println("Message did't pass transformation. Nothing to send."); 99 | } 100 | } 101 | 102 | private static IOMessage buildMessage(IOMessage ioMessage) { 103 | if(config.containsKey("selections")) { 104 | JsonArray selections = config.getJsonArray("selections"); 105 | for (JsonValue selection: selections) { 106 | JsonObject selectionJson = (JsonObject) selection; 107 | if(selectionJson.containsKey("inputtype") && selectionJson.containsKey("inputformat")) { 108 | if (ioMessage.getInfoType().equals(selectionJson.getString("inputtype")) 109 | && ioMessage.getInfoFormat().equals(selectionJson.getString("inputformat"))) { 110 | IOMessage newIoMessage = new IOMessage(); 111 | if(selectionJson.containsKey("outputformat")){ 112 | newIoMessage.setInfoFormat(selectionJson.getString("outputformat")); 113 | } else { 114 | newIoMessage.setInfoFormat(ioMessage.getInfoFormat()); 115 | } 116 | if(selectionJson.containsKey("outputtype")) { 117 | newIoMessage.setInfoType(selectionJson.getString("outputtype")); 118 | } else { 119 | newIoMessage.setInfoType(ioMessage.getInfoType()); 120 | } 121 | newIoMessage.setPublisher(containerId); 122 | newIoMessage.setContentData(buildJsonData(ioMessage.getContentData(), selectionJson)); 123 | return newIoMessage; 124 | } 125 | } 126 | } 127 | } 128 | return null; 129 | } 130 | 131 | private static byte[] buildJsonData(byte[] oldContentData, JsonObject selectionJson) { 132 | JsonReader jsonReader = Json.createReader(new StringReader(new String(oldContentData))); 133 | JsonObject oldJsonData = jsonReader.readObject(); 134 | jsonReader.close(); 135 | JsonObjectBuilder dataBuilder = Json.createObjectBuilder(); 136 | if (selectionJson.containsKey("outputs")) { 137 | JsonArray outputs = selectionJson.getJsonArray("outputs"); 138 | for (JsonValue output: outputs) { 139 | JsonValue value = null; 140 | JsonObject outputJson = (JsonObject) output; 141 | String subselection = ""; 142 | String[] subselections = new String[0]; 143 | if(outputJson.containsKey("subselection")) { 144 | subselection = outputJson.getString("subselection"); 145 | subselections = subselection.split("\\."); 146 | } 147 | if(oldJsonData.containsKey(subselection)) { 148 | value = oldJsonData.get(subselection); 149 | } else if (subselections.length > 1) { 150 | JsonValue subJson = oldJsonData; 151 | for (String subSelect: subselections) { 152 | JsonObject temp = (JsonObject) subJson; 153 | if(temp.containsKey(subSelect)) { 154 | subJson = temp.get(subSelect); 155 | } 156 | } 157 | if(!oldContentData.toString().equals(subJson.toString())) { 158 | value = subJson; 159 | } 160 | } 161 | if(outputJson.containsKey("fieldname")) { 162 | String field = outputJson.getString("fieldname"); 163 | dataBuilder.add(field, buildValue(value, outputJson)); 164 | } else { 165 | dataBuilder.add(subselection, buildValue(value, outputJson)); 166 | } 167 | } 168 | } 169 | JsonObject result = dataBuilder.build(); 170 | if (result.size() == 0) { 171 | return "".getBytes(); 172 | } else { 173 | return result.toString().getBytes(); 174 | } 175 | } 176 | 177 | private static JsonValue buildValue(JsonValue value, JsonObject outputConfig) { 178 | if(outputConfig.containsKey("outputjsonarray") && outputConfig.getBoolean("outputjsonarray")) { 179 | if(value != null) { 180 | if (value instanceof JsonArray) { 181 | return value; 182 | } else { 183 | JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); 184 | arrayBuilder.add(value); 185 | return arrayBuilder.build(); 186 | } 187 | } else { 188 | return Json.createArrayBuilder().build(); 189 | } 190 | } else { 191 | return value!=null ? value : JsonValue.NULL; 192 | } 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /diagnostics/diagnostic.py: -------------------------------------------------------------------------------- 1 | #******************************************************************************** 2 | # Copyright (c) 2020 Edgeworx, Inc. 3 | # 4 | # This program and the accompanying materials are made available under the 5 | # terms of the Eclipse Public License v. 2.0 which is available at 6 | # http://www.eclipse.org/legal/epl-2.0 7 | # 8 | # SPDX-License-Identifier: EPL-2.0 9 | #******************************************************************************** 10 | 11 | import json 12 | import logging 13 | import os 14 | import socket 15 | import threading 16 | import uuid 17 | import urllib2 18 | import time 19 | import subprocess 20 | from iofog_python_sdk.client import IoFogClient, IoFogException 21 | from iofog_python_sdk.listener import * 22 | from iofog_python_sdk.iomessage import IoMessage 23 | 24 | CONTAINER_ID = 'containerid' 25 | TIMESTAMP = 'timestamp' 26 | MESSAGE = 'message' 27 | LOCALHOST = 'localhost' 28 | DIAGNOSTIC_TEST = 'diagnostic/test' 29 | APPLICATION_JSON = 'application/json' 30 | URL = 'url' 31 | REPORT_URL = 'report_url' 32 | PING_REST_BLUE = 'ping_rb' 33 | INTERVAL = 'interval' 34 | IP = 'ip' 35 | PORT = 'port' 36 | HOST = 'host' 37 | SECURE = 'secure' 38 | HTTP = 'http' 39 | HTTPS = 'https' 40 | 41 | TEST_SELFNAME = 'SELFNAME' 42 | TEST_PING = 'PING CHECK' 43 | TEST_PING_WITH_PORT = 'PING WITH PORT CHECK' 44 | TEST_CLIENT_CREATION = 'CLIENT CREATION CHECK' 45 | TEST_HEARTBEAT = 'HEARTBEAT CHECK' 46 | TEST_WEBSOCKETS = 'WEBSOCKETS CHECK' 47 | TEST_GET_CONFIG = 'GET CONFIG CHECK' 48 | TEST_REST_BLUE = 'REST BLUE CHECK' 49 | MESSAGE_SOCKET = 'MESSAGE SOCKET' 50 | CONTROL_SOCKET = 'CONTROL SOCKET' 51 | PUBLIC_REPORTING = 'PUBLIC REPORTING' 52 | 53 | DEFAULT_INTERVAL = 30 54 | 55 | logger = logging.getLogger(__name__) 56 | logger.setLevel(10) 57 | ch = logging.StreamHandler() 58 | ch.setLevel(10) 59 | formatter = logging.Formatter('%(levelname)7s [%(asctime)-15s] - %(message)s') 60 | ch.setFormatter(formatter) 61 | logger.addHandler(ch) 62 | 63 | 64 | class DiagnosticGuru: 65 | def __init__(self): 66 | self.public_report_url = None 67 | self.rest_blue_port = 10500 68 | self.log_container_port = 10555 69 | self.interval = None 70 | self.iofog_client = None 71 | self.report_format = '[{}] {}' 72 | self.current_config = None 73 | self.lock = threading.Lock() 74 | self.diagnostic_id = 'GEN-' + str(uuid.uuid4()).replace('-', '') 75 | self.report_draft = { 76 | CONTAINER_ID: self.diagnostic_id 77 | } 78 | self.heartbeat_timer = None 79 | self.heartbeat_lock = threading.Lock() 80 | self.rb_timer = None 81 | self.rb_lock = threading.Lock() 82 | 83 | def _send_report(self, message): 84 | self.report_draft[MESSAGE] = message 85 | self.report_draft[TIMESTAMP] = long(time.time() * 1000) 86 | try: 87 | req = urllib2.Request(self.public_report_url, json.dumps(self.report_draft), 88 | {'Content-Type': APPLICATION_JSON}) 89 | urllib2.urlopen(req) 90 | except urllib2.HTTPError, e: 91 | self._log(PUBLIC_REPORTING, 'Cannot report to public URL {}: {}'.format(self.public_report_url, e.read()), 92 | logging.ERROR, False) 93 | except urllib2.URLError, e: 94 | self._log(PUBLIC_REPORTING, 'Cannot report to public URL {}: {}'.format(self.public_report_url, e.reason), 95 | logging.ERROR, False) 96 | 97 | def _log(self, test_name, message='', level=logging.INFO, send_report=True): 98 | log_entry = self.report_format.format(test_name, message) 99 | logger.log(level, log_entry) 100 | if send_report and self.public_report_url: 101 | self._send_report(log_entry) 102 | 103 | def _ping(self, host, test=TEST_PING): 104 | with open(os.devnull, 'w') as FNULL: 105 | resp = subprocess.call(['ping', '-c', '3', host], stdout=FNULL, stderr=FNULL) 106 | if resp: 107 | self._log(test, '{} ping failed with error code {}'.format(host, resp), logging.ERROR) 108 | else: 109 | self._log(test, 'Successfully pinged {}'.format(host)) 110 | return resp == 0 111 | 112 | def _ping_port(self, host, port, description='', test=TEST_PING_WITH_PORT): 113 | try: 114 | socket.socket().connect((host, port)) 115 | self._log(test, 'Successfully connected to {}({}, {})'.format(description, host, port)) 116 | return True 117 | except Exception as e: 118 | self._log(test, 119 | 'Error while connecting to {}({}, {}): {}'.format(description, host, port, e), logging.ERROR) 120 | return False 121 | 122 | def _send_heartbeat(self): 123 | with self.heartbeat_lock: 124 | self._log(TEST_HEARTBEAT, '----^v----^v----', logging.DEBUG) 125 | if self.interval: 126 | self.heartbeat_timer = threading.Timer(self.interval, self._send_heartbeat) 127 | self.heartbeat_timer.start() 128 | 129 | def _ping_rb(self): 130 | with self.rb_lock: 131 | self._ping_port(self.iofog_client.host, self.rest_blue_port, 'RestBlue System Container', TEST_REST_BLUE) 132 | if self.interval: 133 | self.rb_timer = threading.Timer(self.interval, self._ping_rb) 134 | self.rb_timer.start() 135 | 136 | def test_client_creation(self): 137 | try: 138 | self.iofog_client = IoFogClient() 139 | self.report_draft[CONTAINER_ID] = self.iofog_client.id 140 | self._log(TEST_CLIENT_CREATION, 'Iofog client created successfully', logging.INFO, False) 141 | except IoFogException as ex: 142 | self._log(TEST_CLIENT_CREATION, 'Error while creating iofog client: {}'.format(ex), logging.ERROR, False) 143 | 144 | def test_heartbeat(self): 145 | self.lock.acquire() 146 | config = self.current_config 147 | self.lock.release() 148 | 149 | if not config: 150 | self._log(TEST_HEARTBEAT, 'Container config is empty. Aborting...', logging.ERROR) 151 | return 152 | 153 | if REPORT_URL not in config: 154 | self._log(TEST_HEARTBEAT, 'No report url is specified in config', logging.INFO) 155 | return 156 | 157 | config = config[REPORT_URL] 158 | port_part = (':' + str(config[PORT])) if PORT in config else '' 159 | protocol_part = (HTTPS if config.get(SECURE, False) else HTTP) + '://' 160 | 161 | if HOST in config and self._ping(config[HOST]): 162 | self.public_report_url = protocol_part + config[HOST] + port_part + config.get(URL, '') 163 | self._log(TEST_HEARTBEAT, 'Successfully connected to {} for report sending'.format(config[HOST])) 164 | self._send_heartbeat() 165 | else: 166 | self._log(TEST_HEARTBEAT, 'Unable to connect to {} for report sending'.format(config.get(HOST)), 167 | logging.WARN) 168 | if IP in config and self._ping(config[IP]): 169 | self.public_report_url = protocol_part + config[IP] + port_part + config.get(URL, '') 170 | self._log(TEST_HEARTBEAT, 'Successfully connected to {} for report sending'.format(config[IP])) 171 | self._send_heartbeat() 172 | else: 173 | self._log(TEST_HEARTBEAT, 174 | 'Unable to connect to {} for report sending. No reports will be sent in this case' 175 | .format(config.get(IP)), logging.ERROR) 176 | self.public_report_url = None 177 | 178 | def update_config(self): 179 | if not self.iofog_client: 180 | self._log(TEST_GET_CONFIG, 'Iofog client is not created. Aborting...', logging.ERROR, False) 181 | return 182 | 183 | self.heartbeat_lock.acquire() 184 | if self.heartbeat_timer: 185 | self.heartbeat_timer.cancel() 186 | self.heartbeat_lock.release() 187 | 188 | self.rb_lock.acquire() 189 | if self.rb_timer: 190 | self.rb_timer.cancel() 191 | self.rb_lock.release() 192 | 193 | attempt_limit = 5 194 | config = None 195 | while attempt_limit > 0: 196 | try: 197 | config = self.iofog_client.get_config() 198 | break 199 | except IoFogException, ex: 200 | attempt_limit -= 1 201 | self._log(TEST_GET_CONFIG, 'Error while fetching config: {}. Retrying...'.format(ex), logging.WARN) 202 | 203 | if attempt_limit == 0: 204 | self._log(TEST_GET_CONFIG, 'Config fetch failed', logging.ERROR) 205 | return 206 | 207 | self.lock.acquire() 208 | self.current_config = config 209 | self.lock.release() 210 | self._log(TEST_GET_CONFIG, 'Successfully fetched config ' + json.dumps(config)) 211 | 212 | self.interval = config.get(INTERVAL, DEFAULT_INTERVAL) 213 | if self.interval < 0: 214 | self._log(TEST_GET_CONFIG, 'Test interval cannot be below zero. Using default value.', 215 | logging.WARN, True) 216 | self.interval = DEFAULT_INTERVAL 217 | self._log(TEST_GET_CONFIG, 'Test interval is ' + str(self.interval) + ' seconds') 218 | 219 | self.test_heartbeat() 220 | if config.get(PING_REST_BLUE, False): 221 | self._ping_rb() 222 | 223 | def test_websockets(self): 224 | if not self.iofog_client: 225 | self._log(TEST_WEBSOCKETS, 'Iofog client is not created. Aborting...', logging.ERROR, False) 226 | return 227 | 228 | class ControlListener(IoFogControlWsListener): 229 | def __init__(self, owner): 230 | IoFogControlWsListener.__init__(self) 231 | self.owner = owner 232 | 233 | def on_control_signal(self): 234 | self.owner._log(CONTROL_SOCKET, 'Got control signal from iofog') 235 | threading.Thread(target=self.owner.update_config).start() 236 | 237 | class MessageListener(IoFogMessageWsListener): 238 | def __init__(self, owner): 239 | IoFogMessageWsListener.__init__(self) 240 | self.owner = owner 241 | 242 | def on_receipt(self, message_id, timestamp): 243 | self.owner._log(MESSAGE_SOCKET, 'Got receipt from iofog: {} {}'.format(message_id, timestamp)) 244 | 245 | def on_message(self, io_msg): 246 | self.owner._log(MESSAGE_SOCKET, 'Successfully received message, sending response...') 247 | new_msg = IoMessage() 248 | new_msg.infotype = DIAGNOSTIC_TEST 249 | new_msg.infoformat = DIAGNOSTIC_TEST 250 | new_msg.contentdata = 'Hello from DIAGNOSTIC container!' 251 | try: 252 | self.owner.iofog_client.post_message_via_socket(new_msg) 253 | self.owner._log(MESSAGE_SOCKET, 'Successfully sent response') 254 | except IoFogException as e: 255 | self.owner._log(MESSAGE_SOCKET, 'Error while sending message to iofog: {}'.format(e), logging.ERROR) 256 | 257 | self.iofog_client.establish_control_ws_connection(ControlListener(self)) 258 | self.iofog_client.establish_message_ws_connection(MessageListener(self)) 259 | 260 | 261 | guru = DiagnosticGuru() 262 | guru.test_client_creation() 263 | guru.test_websockets() 264 | guru.update_config() 265 | -------------------------------------------------------------------------------- /sensors-data/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@iofog/nodejs-sdk@^0.0.1": 6 | version "0.0.1" 7 | resolved "https://registry.yarnpkg.com/@iofog/nodejs-sdk/-/nodejs-sdk-0.0.1.tgz#0d9d52b19ecd74f819ab3fb6b0eb85805b29b090" 8 | dependencies: 9 | console-stamp "0.2.2" 10 | request "2.70.0" 11 | ws "1.0.1" 12 | 13 | ansi-regex@^2.0.0: 14 | version "2.1.1" 15 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 16 | 17 | ansi-styles@^2.2.1: 18 | version "2.2.1" 19 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 20 | 21 | array-find-index@^1.0.1: 22 | version "1.0.2" 23 | resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" 24 | 25 | asn1@~0.2.3: 26 | version "0.2.4" 27 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" 28 | dependencies: 29 | safer-buffer "~2.1.0" 30 | 31 | assert-plus@1.0.0, assert-plus@^1.0.0: 32 | version "1.0.0" 33 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 34 | 35 | assert-plus@^0.2.0: 36 | version "0.2.0" 37 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" 38 | 39 | async@^2.0.1: 40 | version "2.6.1" 41 | resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" 42 | dependencies: 43 | lodash "^4.17.10" 44 | 45 | aws-sign2@~0.6.0: 46 | version "0.6.0" 47 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" 48 | 49 | aws4@^1.2.1: 50 | version "1.8.0" 51 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" 52 | 53 | bcrypt-pbkdf@^1.0.0: 54 | version "1.0.2" 55 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" 56 | dependencies: 57 | tweetnacl "^0.14.3" 58 | 59 | bl@~1.1.2: 60 | version "1.1.2" 61 | resolved "http://registry.npmjs.org/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" 62 | dependencies: 63 | readable-stream "~2.0.5" 64 | 65 | boom@2.x.x: 66 | version "2.10.1" 67 | resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" 68 | dependencies: 69 | hoek "2.x.x" 70 | 71 | builtin-modules@^1.0.0: 72 | version "1.1.1" 73 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 74 | 75 | camelcase-keys@^2.0.0: 76 | version "2.1.0" 77 | resolved "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" 78 | dependencies: 79 | camelcase "^2.0.0" 80 | map-obj "^1.0.0" 81 | 82 | camelcase@^2.0.0: 83 | version "2.1.1" 84 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" 85 | 86 | caseless@~0.11.0: 87 | version "0.11.0" 88 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" 89 | 90 | chalk@^1.1.1: 91 | version "1.1.3" 92 | resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 93 | dependencies: 94 | ansi-styles "^2.2.1" 95 | escape-string-regexp "^1.0.2" 96 | has-ansi "^2.0.0" 97 | strip-ansi "^3.0.0" 98 | supports-color "^2.0.0" 99 | 100 | combined-stream@^1.0.5, combined-stream@~1.0.5: 101 | version "1.0.7" 102 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" 103 | dependencies: 104 | delayed-stream "~1.0.0" 105 | 106 | commander@^2.9.0: 107 | version "2.19.0" 108 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" 109 | 110 | console-stamp@0.2.2: 111 | version "0.2.2" 112 | resolved "http://registry.npmjs.org/console-stamp/-/console-stamp-0.2.2.tgz#4fd7ce2692502dac37538a2d498fb9a9f86e7ae3" 113 | dependencies: 114 | chalk "^1.1.1" 115 | dateformat "^1.0.11" 116 | merge "^1.2.0" 117 | 118 | core-util-is@1.0.2, core-util-is@~1.0.0: 119 | version "1.0.2" 120 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 121 | 122 | cryptiles@2.x.x: 123 | version "2.0.5" 124 | resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" 125 | dependencies: 126 | boom "2.x.x" 127 | 128 | currently-unhandled@^0.4.1: 129 | version "0.4.1" 130 | resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" 131 | dependencies: 132 | array-find-index "^1.0.1" 133 | 134 | dashdash@^1.12.0: 135 | version "1.14.1" 136 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 137 | dependencies: 138 | assert-plus "^1.0.0" 139 | 140 | dateformat@^1.0.11: 141 | version "1.0.12" 142 | resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" 143 | dependencies: 144 | get-stdin "^4.0.1" 145 | meow "^3.3.0" 146 | 147 | decamelize@^1.1.2: 148 | version "1.2.0" 149 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 150 | 151 | delayed-stream@~1.0.0: 152 | version "1.0.0" 153 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 154 | 155 | ecc-jsbn@~0.1.1: 156 | version "0.1.2" 157 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" 158 | dependencies: 159 | jsbn "~0.1.0" 160 | safer-buffer "^2.1.0" 161 | 162 | error-ex@^1.2.0: 163 | version "1.3.2" 164 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 165 | dependencies: 166 | is-arrayish "^0.2.1" 167 | 168 | escape-string-regexp@^1.0.2: 169 | version "1.0.5" 170 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 171 | 172 | extend@~3.0.0: 173 | version "3.0.2" 174 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 175 | 176 | extsprintf@1.3.0: 177 | version "1.3.0" 178 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 179 | 180 | extsprintf@^1.2.0: 181 | version "1.4.0" 182 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" 183 | 184 | find-up@^1.0.0: 185 | version "1.1.2" 186 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" 187 | dependencies: 188 | path-exists "^2.0.0" 189 | pinkie-promise "^2.0.0" 190 | 191 | forever-agent@~0.6.1: 192 | version "0.6.1" 193 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 194 | 195 | form-data@~1.0.0-rc3: 196 | version "1.0.1" 197 | resolved "http://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" 198 | dependencies: 199 | async "^2.0.1" 200 | combined-stream "^1.0.5" 201 | mime-types "^2.1.11" 202 | 203 | generate-function@^2.0.0: 204 | version "2.3.1" 205 | resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" 206 | dependencies: 207 | is-property "^1.0.2" 208 | 209 | generate-object-property@^1.1.0: 210 | version "1.2.0" 211 | resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" 212 | dependencies: 213 | is-property "^1.0.0" 214 | 215 | get-stdin@^4.0.1: 216 | version "4.0.1" 217 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" 218 | 219 | getpass@^0.1.1: 220 | version "0.1.7" 221 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 222 | dependencies: 223 | assert-plus "^1.0.0" 224 | 225 | graceful-fs@^4.1.2: 226 | version "4.1.11" 227 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 228 | 229 | har-validator@~2.0.6: 230 | version "2.0.6" 231 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" 232 | dependencies: 233 | chalk "^1.1.1" 234 | commander "^2.9.0" 235 | is-my-json-valid "^2.12.4" 236 | pinkie-promise "^2.0.0" 237 | 238 | has-ansi@^2.0.0: 239 | version "2.0.0" 240 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 241 | dependencies: 242 | ansi-regex "^2.0.0" 243 | 244 | hawk@~3.1.3: 245 | version "3.1.3" 246 | resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" 247 | dependencies: 248 | boom "2.x.x" 249 | cryptiles "2.x.x" 250 | hoek "2.x.x" 251 | sntp "1.x.x" 252 | 253 | hoek@2.x.x: 254 | version "2.16.3" 255 | resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" 256 | 257 | hosted-git-info@^2.1.4: 258 | version "2.7.1" 259 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" 260 | 261 | http-signature@~1.1.0: 262 | version "1.1.1" 263 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" 264 | dependencies: 265 | assert-plus "^0.2.0" 266 | jsprim "^1.2.2" 267 | sshpk "^1.7.0" 268 | 269 | indent-string@^2.1.0: 270 | version "2.1.0" 271 | resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" 272 | dependencies: 273 | repeating "^2.0.0" 274 | 275 | inherits@~2.0.1: 276 | version "2.0.3" 277 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 278 | 279 | is-arrayish@^0.2.1: 280 | version "0.2.1" 281 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 282 | 283 | is-builtin-module@^1.0.0: 284 | version "1.0.0" 285 | resolved "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" 286 | dependencies: 287 | builtin-modules "^1.0.0" 288 | 289 | is-finite@^1.0.0: 290 | version "1.0.2" 291 | resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" 292 | dependencies: 293 | number-is-nan "^1.0.0" 294 | 295 | is-my-ip-valid@^1.0.0: 296 | version "1.0.0" 297 | resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" 298 | 299 | is-my-json-valid@^2.12.4: 300 | version "2.19.0" 301 | resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" 302 | dependencies: 303 | generate-function "^2.0.0" 304 | generate-object-property "^1.1.0" 305 | is-my-ip-valid "^1.0.0" 306 | jsonpointer "^4.0.0" 307 | xtend "^4.0.0" 308 | 309 | is-property@^1.0.0, is-property@^1.0.2: 310 | version "1.0.2" 311 | resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" 312 | 313 | is-typedarray@~1.0.0: 314 | version "1.0.0" 315 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 316 | 317 | is-utf8@^0.2.0: 318 | version "0.2.1" 319 | resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" 320 | 321 | isarray@~1.0.0: 322 | version "1.0.0" 323 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 324 | 325 | isstream@~0.1.2: 326 | version "0.1.2" 327 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 328 | 329 | jsbn@~0.1.0: 330 | version "0.1.1" 331 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 332 | 333 | json-schema@0.2.3: 334 | version "0.2.3" 335 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 336 | 337 | json-stringify-safe@~5.0.1: 338 | version "5.0.1" 339 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 340 | 341 | jsonpointer@^4.0.0: 342 | version "4.0.1" 343 | resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" 344 | 345 | jsprim@^1.2.2: 346 | version "1.4.1" 347 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" 348 | dependencies: 349 | assert-plus "1.0.0" 350 | extsprintf "1.3.0" 351 | json-schema "0.2.3" 352 | verror "1.10.0" 353 | 354 | load-json-file@^1.0.0: 355 | version "1.1.0" 356 | resolved "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" 357 | dependencies: 358 | graceful-fs "^4.1.2" 359 | parse-json "^2.2.0" 360 | pify "^2.0.0" 361 | pinkie-promise "^2.0.0" 362 | strip-bom "^2.0.0" 363 | 364 | lodash@^4.17.10: 365 | version "4.17.11" 366 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" 367 | 368 | loud-rejection@^1.0.0: 369 | version "1.6.0" 370 | resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" 371 | dependencies: 372 | currently-unhandled "^0.4.1" 373 | signal-exit "^3.0.0" 374 | 375 | map-obj@^1.0.0, map-obj@^1.0.1: 376 | version "1.0.1" 377 | resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" 378 | 379 | meow@^3.3.0: 380 | version "3.7.0" 381 | resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" 382 | dependencies: 383 | camelcase-keys "^2.0.0" 384 | decamelize "^1.1.2" 385 | loud-rejection "^1.0.0" 386 | map-obj "^1.0.1" 387 | minimist "^1.1.3" 388 | normalize-package-data "^2.3.4" 389 | object-assign "^4.0.1" 390 | read-pkg-up "^1.0.1" 391 | redent "^1.0.0" 392 | trim-newlines "^1.0.0" 393 | 394 | merge@^1.2.0: 395 | version "1.2.0" 396 | resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" 397 | 398 | mime-db@~1.36.0: 399 | version "1.36.0" 400 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" 401 | 402 | mime-types@^2.1.11, mime-types@~2.1.7: 403 | version "2.1.20" 404 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" 405 | dependencies: 406 | mime-db "~1.36.0" 407 | 408 | minimist@^1.1.3: 409 | version "1.2.0" 410 | resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 411 | 412 | node-uuid@~1.4.7: 413 | version "1.4.8" 414 | resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" 415 | 416 | normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: 417 | version "2.4.0" 418 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" 419 | dependencies: 420 | hosted-git-info "^2.1.4" 421 | is-builtin-module "^1.0.0" 422 | semver "2 || 3 || 4 || 5" 423 | validate-npm-package-license "^3.0.1" 424 | 425 | number-is-nan@^1.0.0: 426 | version "1.0.1" 427 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 428 | 429 | oauth-sign@~0.8.1: 430 | version "0.8.2" 431 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" 432 | 433 | object-assign@^4.0.1: 434 | version "4.1.1" 435 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 436 | 437 | options@>=0.0.5: 438 | version "0.0.6" 439 | resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" 440 | 441 | parse-json@^2.2.0: 442 | version "2.2.0" 443 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" 444 | dependencies: 445 | error-ex "^1.2.0" 446 | 447 | path-exists@^2.0.0: 448 | version "2.1.0" 449 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" 450 | dependencies: 451 | pinkie-promise "^2.0.0" 452 | 453 | path-type@^1.0.0: 454 | version "1.1.0" 455 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" 456 | dependencies: 457 | graceful-fs "^4.1.2" 458 | pify "^2.0.0" 459 | pinkie-promise "^2.0.0" 460 | 461 | pify@^2.0.0: 462 | version "2.3.0" 463 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 464 | 465 | pinkie-promise@^2.0.0: 466 | version "2.0.1" 467 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 468 | dependencies: 469 | pinkie "^2.0.0" 470 | 471 | pinkie@^2.0.0: 472 | version "2.0.4" 473 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 474 | 475 | process-nextick-args@~1.0.6: 476 | version "1.0.7" 477 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 478 | 479 | qs@~6.1.0: 480 | version "6.1.2" 481 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.1.2.tgz#b59d8925d0c999ef6d63acf4ac5abb0adaa24b54" 482 | 483 | read-pkg-up@^1.0.1: 484 | version "1.0.1" 485 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" 486 | dependencies: 487 | find-up "^1.0.0" 488 | read-pkg "^1.0.0" 489 | 490 | read-pkg@^1.0.0: 491 | version "1.1.0" 492 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" 493 | dependencies: 494 | load-json-file "^1.0.0" 495 | normalize-package-data "^2.3.2" 496 | path-type "^1.0.0" 497 | 498 | readable-stream@~2.0.5: 499 | version "2.0.6" 500 | resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" 501 | dependencies: 502 | core-util-is "~1.0.0" 503 | inherits "~2.0.1" 504 | isarray "~1.0.0" 505 | process-nextick-args "~1.0.6" 506 | string_decoder "~0.10.x" 507 | util-deprecate "~1.0.1" 508 | 509 | redent@^1.0.0: 510 | version "1.0.0" 511 | resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" 512 | dependencies: 513 | indent-string "^2.1.0" 514 | strip-indent "^1.0.1" 515 | 516 | repeating@^2.0.0: 517 | version "2.0.1" 518 | resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" 519 | dependencies: 520 | is-finite "^1.0.0" 521 | 522 | request@2.70.0: 523 | version "2.70.0" 524 | resolved "http://registry.npmjs.org/request/-/request-2.70.0.tgz#7ecf8437d6fb553e92e2981a411b9ee2aadd7cce" 525 | dependencies: 526 | aws-sign2 "~0.6.0" 527 | aws4 "^1.2.1" 528 | bl "~1.1.2" 529 | caseless "~0.11.0" 530 | combined-stream "~1.0.5" 531 | extend "~3.0.0" 532 | forever-agent "~0.6.1" 533 | form-data "~1.0.0-rc3" 534 | har-validator "~2.0.6" 535 | hawk "~3.1.3" 536 | http-signature "~1.1.0" 537 | is-typedarray "~1.0.0" 538 | isstream "~0.1.2" 539 | json-stringify-safe "~5.0.1" 540 | mime-types "~2.1.7" 541 | node-uuid "~1.4.7" 542 | oauth-sign "~0.8.1" 543 | qs "~6.1.0" 544 | stringstream "~0.0.4" 545 | tough-cookie "~2.2.0" 546 | tunnel-agent "~0.4.1" 547 | 548 | safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: 549 | version "2.1.2" 550 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 551 | 552 | "semver@2 || 3 || 4 || 5": 553 | version "5.6.0" 554 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" 555 | 556 | signal-exit@^3.0.0: 557 | version "3.0.2" 558 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 559 | 560 | sntp@1.x.x: 561 | version "1.0.9" 562 | resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" 563 | dependencies: 564 | hoek "2.x.x" 565 | 566 | spdx-correct@^3.0.0: 567 | version "3.0.2" 568 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.2.tgz#19bb409e91b47b1ad54159243f7312a858db3c2e" 569 | dependencies: 570 | spdx-expression-parse "^3.0.0" 571 | spdx-license-ids "^3.0.0" 572 | 573 | spdx-exceptions@^2.1.0: 574 | version "2.2.0" 575 | resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" 576 | 577 | spdx-expression-parse@^3.0.0: 578 | version "3.0.0" 579 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" 580 | dependencies: 581 | spdx-exceptions "^2.1.0" 582 | spdx-license-ids "^3.0.0" 583 | 584 | spdx-license-ids@^3.0.0: 585 | version "3.0.1" 586 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz#e2a303236cac54b04031fa7a5a79c7e701df852f" 587 | 588 | sshpk@^1.7.0: 589 | version "1.15.1" 590 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.1.tgz#b79a089a732e346c6e0714830f36285cd38191a2" 591 | dependencies: 592 | asn1 "~0.2.3" 593 | assert-plus "^1.0.0" 594 | bcrypt-pbkdf "^1.0.0" 595 | dashdash "^1.12.0" 596 | ecc-jsbn "~0.1.1" 597 | getpass "^0.1.1" 598 | jsbn "~0.1.0" 599 | safer-buffer "^2.0.2" 600 | tweetnacl "~0.14.0" 601 | 602 | string_decoder@~0.10.x: 603 | version "0.10.31" 604 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 605 | 606 | stringstream@~0.0.4: 607 | version "0.0.6" 608 | resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" 609 | 610 | strip-ansi@^3.0.0: 611 | version "3.0.1" 612 | resolved "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 613 | dependencies: 614 | ansi-regex "^2.0.0" 615 | 616 | strip-bom@^2.0.0: 617 | version "2.0.0" 618 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" 619 | dependencies: 620 | is-utf8 "^0.2.0" 621 | 622 | strip-indent@^1.0.1: 623 | version "1.0.1" 624 | resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" 625 | dependencies: 626 | get-stdin "^4.0.1" 627 | 628 | supports-color@^2.0.0: 629 | version "2.0.0" 630 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 631 | 632 | tough-cookie@~2.2.0: 633 | version "2.2.2" 634 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" 635 | 636 | trim-newlines@^1.0.0: 637 | version "1.0.0" 638 | resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" 639 | 640 | tunnel-agent@~0.4.1: 641 | version "0.4.3" 642 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" 643 | 644 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 645 | version "0.14.5" 646 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 647 | 648 | ultron@1.0.x: 649 | version "1.0.2" 650 | resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" 651 | 652 | util-deprecate@~1.0.1: 653 | version "1.0.2" 654 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 655 | 656 | validate-npm-package-license@^3.0.1: 657 | version "3.0.4" 658 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" 659 | dependencies: 660 | spdx-correct "^3.0.0" 661 | spdx-expression-parse "^3.0.0" 662 | 663 | verror@1.10.0: 664 | version "1.10.0" 665 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" 666 | dependencies: 667 | assert-plus "^1.0.0" 668 | core-util-is "1.0.2" 669 | extsprintf "^1.2.0" 670 | 671 | ws@1.0.1: 672 | version "1.0.1" 673 | resolved "http://registry.npmjs.org/ws/-/ws-1.0.1.tgz#7d0b2a2e58cddd819039c29c9de65045e1b310e9" 674 | dependencies: 675 | options ">=0.0.5" 676 | ultron "1.0.x" 677 | 678 | xtend@^4.0.0: 679 | version "4.0.1" 680 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 681 | --------------------------------------------------------------------------------