├── test ├── CustomerC.ref ├── FmtConciseO.json ├── FmtConciseA.json ├── FmtConciseO.ref ├── FmtConciseA.ref ├── CustomerP.json ├── CustomerPC.ref ├── MenuItemsJ2S.ref ├── Customer.json ├── CustomerSC.ref ├── CustomerP.ref ├── CustomerPS.ref ├── CustomerSI.ref ├── Customer.ref ├── Goods.json ├── GoodsJ2S.ref ├── CustomerJ2S.ref ├── Schedules.json ├── MenuItems.json ├── Books.ref ├── Schedules.ref ├── SchedulesSI.ref ├── SchedulesJ2S.ref ├── Books.xml ├── SmartyStreetsCUC.json ├── SmartyStreets.json ├── SmartyStreetsCLK.json ├── SmartyStreetsJ2S.ref └── friendfeed_oww.json ├── go.mod.clean ├── .gitignore ├── jsonfiddle_cliGen.sh ├── go.mod ├── .goreleaser.yml ├── imp_esc.go ├── imp_x2j.go ├── LICENSE ├── imp_sort.go ├── imp_fmt.go ├── imp_j2s.go ├── cmd_x2j.go ├── cmd_esc.go ├── cmd_sort.go ├── cmd_fmt.go ├── cmd_j2s.go ├── prop_fmt_test.go ├── jsonfiddle_main.go ├── .github └── workflows │ └── go-release-build.yml ├── jsonfiddle_test.go ├── go.sum ├── prop_fmt.go ├── jsonfiddle_cli.yaml ├── README.e.md ├── jsonfiddle_cliDef.go └── README.md /test/CustomerC.ref: -------------------------------------------------------------------------------- 1 | Customer.json -------------------------------------------------------------------------------- /test/FmtConciseO.json: -------------------------------------------------------------------------------- 1 | {"users":[{"active":true,"id":1},{"active":false,"id":2}]} 2 | -------------------------------------------------------------------------------- /test/FmtConciseA.json: -------------------------------------------------------------------------------- 1 | [{"city":"NYC","name":"Alice"},{"city":"LA","name":"Bob"},{"city":"SF","name":"Charlie"}] 2 | -------------------------------------------------------------------------------- /test/FmtConciseO.ref: -------------------------------------------------------------------------------- 1 | { "users": [ 2 | {"active":true,"id":1}, 3 | {"active":false,"id":2} 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /go.mod.clean: -------------------------------------------------------------------------------- 1 | module jsonfiddle 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.1 6 | 7 | require golang.org/x/net v0.43.0 // indirect 8 | -------------------------------------------------------------------------------- /test/FmtConciseA.ref: -------------------------------------------------------------------------------- 1 | [ 2 | {"city":"NYC","name":"Alice"}, 3 | {"city":"LA","name":"Bob"}, 4 | {"city":"SF","name":"Charlie"} 5 | ] 6 | -------------------------------------------------------------------------------- /test/CustomerP.json: -------------------------------------------------------------------------------- 1 | {"firstName":"{{C_firstName}}","lastName":"{{C_lastName}}","age":{{C_age}},"address":{"streetAddress":"{{C_address1}}","city":"{{C_city}}","state":"NY","postalCode":"10021"}} 2 | -------------------------------------------------------------------------------- /test/CustomerPC.ref: -------------------------------------------------------------------------------- 1 | {"firstName":"<>","lastName":"<>","age":"<>","address":{"streetAddress":"<>","city":"<>","state":"NY","postalCode":"10021"}} 2 | -------------------------------------------------------------------------------- /test/MenuItemsJ2S.ref: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type MenuItems struct { 4 | Menu struct { 5 | Header string `json:"header"` 6 | Items []struct { 7 | ID string `json:"id"` 8 | } `json:"items"` 9 | } `json:"menu"` 10 | } 11 | -------------------------------------------------------------------------------- /test/Customer.json: -------------------------------------------------------------------------------- 1 | {"firstName":"John","lastName":"Smith","age":25,"address":{"streetAddress":"21 2nd Street","city":"New York","state":"NY","postalCode":"10021"},"phoneNumber":[{"type":"home","number":"212 555-1234"},{"type":"fax","number":"646 555-4567"}]} 2 | -------------------------------------------------------------------------------- /test/CustomerSC.ref: -------------------------------------------------------------------------------- 1 | {"address":{"city":"New York","postalCode":"10021","state":"NY","streetAddress":"21 2nd Street"},"age":25,"firstName":"John","lastName":"Smith","phoneNumber":[{"number":"212 555-1234","type":"home"},{"number":"646 555-4567","type":"fax"}]} 2 | -------------------------------------------------------------------------------- /test/CustomerP.ref: -------------------------------------------------------------------------------- 1 | { 2 | "firstName": "<>", 3 | "lastName": "<>", 4 | "age": "<>", 5 | "address": { 6 | "streetAddress": "<>", 7 | "city": "<>", 8 | "state": "NY", 9 | "postalCode": "10021" 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /test/CustomerPS.ref: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "city": "\u003c\u003cC_city\u003e\u003e", 4 | "postalCode": "10021", 5 | "state": "NY", 6 | "streetAddress": "\u003c\u003cC_address1\u003e\u003e" 7 | }, 8 | "age": "\u003c\u003cC_age\u003e\u003e", 9 | "firstName": "\u003c\u003cC_firstName\u003e\u003e", 10 | "lastName": "\u003c\u003cC_lastName\u003e\u003e" 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | jsonfiddle 16 | jsonfiddle.exe 17 | test/*.got 18 | -------------------------------------------------------------------------------- /test/CustomerSI.ref: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "city": "New York", 4 | "postalCode": "10021", 5 | "state": "NY", 6 | "streetAddress": "21 2nd Street" 7 | }, 8 | "age": 25, 9 | "firstName": "John", 10 | "lastName": "Smith", 11 | "phoneNumber": [ 12 | { 13 | "number": "212 555-1234", 14 | "type": "home" 15 | }, 16 | { 17 | "number": "646 555-4567", 18 | "type": "fax" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /test/Customer.ref: -------------------------------------------------------------------------------- 1 | { 2 | "firstName": "John", 3 | "lastName": "Smith", 4 | "age": 25, 5 | "address": { 6 | "streetAddress": "21 2nd Street", 7 | "city": "New York", 8 | "state": "NY", 9 | "postalCode": "10021" 10 | }, 11 | "phoneNumber": [ 12 | { 13 | "type": "home", 14 | "number": "212 555-1234" 15 | }, 16 | { 17 | "type": "fax", 18 | "number": "646 555-4567" 19 | } 20 | ] 21 | } 22 | 23 | -------------------------------------------------------------------------------- /test/Goods.json: -------------------------------------------------------------------------------- 1 | {"store":{"book":[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],"bicycle":{"color":"red","price":19.95}},"expensive":10} -------------------------------------------------------------------------------- /test/GoodsJ2S.ref: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Goods struct { 4 | Expensive int64 `json:"expensive"` 5 | Store struct { 6 | Bicycle struct { 7 | Color string `json:"color"` 8 | Price float64 `json:"price"` 9 | } `json:"bicycle"` 10 | Book []struct { 11 | Author string `json:"author"` 12 | Category string `json:"category"` 13 | Isbn string `json:"isbn"` 14 | Price float64 `json:"price"` 15 | Title string `json:"title"` 16 | } `json:"book"` 17 | } `json:"store"` 18 | } 19 | -------------------------------------------------------------------------------- /test/CustomerJ2S.ref: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Customer struct { 4 | Address struct { 5 | City string `json:"city"` 6 | PostalCode string `json:"postalCode"` 7 | State string `json:"state"` 8 | StreetAddress string `json:"streetAddress"` 9 | } `json:"address"` 10 | Age int64 `json:"age"` 11 | FirstName string `json:"firstName"` 12 | LastName string `json:"lastName"` 13 | PhoneNumber []struct { 14 | Number string `json:"number"` 15 | Type string `json:"type"` 16 | } `json:"phoneNumber"` 17 | } 18 | -------------------------------------------------------------------------------- /test/Schedules.json: -------------------------------------------------------------------------------- 1 | {"DaysCfg":{"Range":{"lowerDate":"2017-07-28T00:00:00.000-04:00","upperDate":"2017-08-04T00:00:00.000-04:00"},"DaysInPeriod":8,"DaysToSchedule":[0,1,2,3,4,5,6]},"DepartmentsID":[138837,139734,141934,142436,149687,151049],"EmployeesID":[5039,5170,5889,6051,6236,7208,7281,8776,8781,8936,9261],"EndDate":"2017-08-03T23:59:00.000-04:00","IntervalSize":15,"IsActivitiesEnabled":true,"ModifyExisting":false,"OrignId":134721,"PrimaryOption":0,"SchoolDays":[],"ScheduleChanges":[],"StartDate":"2017-07-28T00:00:00.000-04:00","ZonesToSchedule":[5,4,6,3,3,3,2,14]} -------------------------------------------------------------------------------- /jsonfiddle_cliGen.sh: -------------------------------------------------------------------------------- 1 | prj=jsonfiddle 2 | pwd=`pwd` 3 | srcDir=$GOPATH/src/github.com/go-easygen/easygen/test 4 | cd $srcDir || srcDir=/usr/share/gocode/src/github.com/go-easygen/easygen/test 5 | cd $srcDir || srcDir=/usr/share/doc/easygen/examples 6 | [ -d "$srcDir" ] || { 7 | echo No template file found 8 | exit 1 9 | } 10 | 11 | set -x 12 | 13 | cd $srcDir 14 | easygen commandlineGoFlags.header,commandlineGoFlags.ityped.tmpl,commandlineGoFlags "$pwd/$prj"_cli | gofmt > "$pwd/$prj"_cliDef.go 15 | 16 | cd $pwd 17 | go build -v 18 | echo ${prj}_cliDef.go generated successful 19 | -------------------------------------------------------------------------------- /test/MenuItems.json: -------------------------------------------------------------------------------- 1 | {"menu":{"header":"xProgress SVG Viewer","items":[{"id":"Open"},{"id":"OpenNew","label":"Open New"},null,{"id":"ZoomIn","label":"Zoom In"},{"id":"ZoomOut","label":"Zoom Out"},{"id":"OriginalView","label":"Original View"},null,{"id":"Quality"},{"id":"Pause"},{"id":"Mute"},null,{"id":"Find","label":"Find..."},{"id":"FindAgain","label":"Find Again"},{"id":"Copy"},{"id":"CopyAgain","label":"Copy Again"},{"id":"CopySVG","label":"Copy SVG"},{"id":"ViewSVG","label":"View SVG"},{"id":"ViewSource","label":"View Source"},{"id":"SaveAs","label":"Save As"},null,{"id":"Help"},{"id":"About","label":"About xProgress CVG Viewer..."}]}} 2 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module jsonfiddle 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.1 6 | 7 | require ( 8 | github.com/basgys/goxml2json v1.1.0 9 | github.com/go-easygen/go-flags v1.5.3 10 | github.com/go-jsonfile/gojson v0.0.0-20170804141630-ca37eb6137fb 11 | github.com/suntong/enum v2.0.1+incompatible 12 | ) 13 | 14 | require ( 15 | github.com/bitly/go-simplejson v0.5.1 // indirect 16 | github.com/labstack/gommon v0.4.2 // indirect 17 | github.com/mattn/go-colorable v0.1.13 // indirect 18 | github.com/mattn/go-isatty v0.0.20 // indirect 19 | golang.org/x/net v0.43.0 // indirect 20 | golang.org/x/sys v0.35.0 // indirect 21 | golang.org/x/text v0.28.0 // indirect 22 | gopkg.in/suntong/enum.v1 v1.0.0 // indirect 23 | gopkg.in/yaml.v2 v2.4.0 // indirect 24 | ) 25 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: jsonfiddle 2 | 3 | archives: 4 | - format: tar.gz 5 | wrap_in_directory: true 6 | format_overrides: 7 | - goos: windows 8 | format: zip 9 | # remove README and LICENSE 10 | files: 11 | - none* 12 | 13 | builds: 14 | - env: [CGO_ENABLED=0] 15 | goos: 16 | - linux 17 | - windows 18 | - darwin 19 | goarch: 20 | - amd64 21 | - arm64 22 | 23 | # Path to main.go file or main package. 24 | # Default is `.`. 25 | 26 | nfpms: 27 | - maintainer: Tong Sun 28 | description: jsonfiddle - Tool to fiddle with json strings 29 | homepage: https://github.com/go-jsonfiddle/jsonfiddle 30 | license: MIT 31 | formats: 32 | - deb 33 | - rpm 34 | - apk 35 | -------------------------------------------------------------------------------- /test/Books.ref: -------------------------------------------------------------------------------- 1 | {"catalog": {"book": [{"-id": "bk101", "author": "Gambardella, Matthew", "title": "XML Developer's Guide", "genre": "Computer", "price": "44.95", "publish_date": "2000-10-01", "description": "An in-depth look at creating applications \n with XML."}, {"price": "5.95", "publish_date": "2000-12-16", "description": "A former architect battles corporate zombies, \n an evil sorceress, and her own childhood to become queen \n of the world.", "-id": "bk102", "author": "Ralls, Kim", "title": "Midnight Rain", "genre": "Fantasy"}, {"genre": "Fantasy", "price": "5.95", "publish_date": "2000-11-17", "description": "After the collapse of a nanotechnology \n society in England, the young survivors lay the \n foundation for a new society.", "-id": "bk103", "author": "Corets, Eva", "title": "Maeve Ascendant"}]}} 2 | 3 | -------------------------------------------------------------------------------- /imp_esc.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2017-2023, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "encoding/json" 11 | "fmt" 12 | 13 | "github.com/go-easygen/go-flags/clis" 14 | ) 15 | 16 | // *** Sub-command: esc *** 17 | // Exec implements the business logic of command `esc` 18 | func (x *EscCommand) Exec(args []string) error { 19 | data := clis.ReadInput(x.Filei) 20 | 21 | out, err := json.Marshal(string(data)) 22 | clis.AbortOn("Formatting input", err) 23 | 24 | fileO := clis.GetOutputStream(x.Fileo) 25 | defer fileO.Close() 26 | 27 | fmt.Fprintf(fileO, "%s", out) 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /test/Schedules.ref: -------------------------------------------------------------------------------- 1 | { 2 | "DaysCfg": { 3 | "Range": { 4 | "lowerDate": "2017-07-28T00:00:00.000-04:00", 5 | "upperDate": "2017-08-04T00:00:00.000-04:00" 6 | }, 7 | "DaysInPeriod": 8, 8 | "DaysToSchedule": [ 9 | 0, 10 | 1, 11 | 2, 12 | 3, 13 | 4, 14 | 5, 15 | 6 16 | ] 17 | }, 18 | "DepartmentsID": [ 19 | 138837, 20 | 139734, 21 | 141934, 22 | 142436, 23 | 149687, 24 | 151049 25 | ], 26 | "EmployeesID": [ 27 | 5039, 28 | 5170, 29 | 5889, 30 | 6051, 31 | 6236, 32 | 7208, 33 | 7281, 34 | 8776, 35 | 8781, 36 | 8936, 37 | 9261 38 | ], 39 | "EndDate": "2017-08-03T23:59:00.000-04:00", 40 | "IntervalSize": 15, 41 | "IsActivitiesEnabled": true, 42 | "ModifyExisting": false, 43 | "OrignId": 134721, 44 | "PrimaryOption": 0, 45 | "SchoolDays": [], 46 | "ScheduleChanges": [], 47 | "StartDate": "2017-07-28T00:00:00.000-04:00", 48 | "ZonesToSchedule": [ 49 | 5, 50 | 4, 51 | 6, 52 | 3, 53 | 3, 54 | 3, 55 | 2, 56 | 14 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /test/SchedulesSI.ref: -------------------------------------------------------------------------------- 1 | { 2 | "DaysCfg": { 3 | "DaysInPeriod": 8, 4 | "DaysToSchedule": [ 5 | 0, 6 | 1, 7 | 2, 8 | 3, 9 | 4, 10 | 5, 11 | 6 12 | ], 13 | "Range": { 14 | "lowerDate": "2017-07-28T00:00:00.000-04:00", 15 | "upperDate": "2017-08-04T00:00:00.000-04:00" 16 | } 17 | }, 18 | "DepartmentsID": [ 19 | 138837, 20 | 139734, 21 | 141934, 22 | 142436, 23 | 149687, 24 | 151049 25 | ], 26 | "EmployeesID": [ 27 | 5039, 28 | 5170, 29 | 5889, 30 | 6051, 31 | 6236, 32 | 7208, 33 | 7281, 34 | 8776, 35 | 8781, 36 | 8936, 37 | 9261 38 | ], 39 | "EndDate": "2017-08-03T23:59:00.000-04:00", 40 | "IntervalSize": 15, 41 | "IsActivitiesEnabled": true, 42 | "ModifyExisting": false, 43 | "OrignId": 134721, 44 | "PrimaryOption": 0, 45 | "ScheduleChanges": [], 46 | "SchoolDays": [], 47 | "StartDate": "2017-07-28T00:00:00.000-04:00", 48 | "ZonesToSchedule": [ 49 | 5, 50 | 4, 51 | 6, 52 | 3, 53 | 3, 54 | 3, 55 | 2, 56 | 14 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /test/SchedulesJ2S.ref: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Schedules struct { 4 | DaysCfg struct { 5 | DaysInPeriod int64 `json:"DaysInPeriod"` 6 | DaysToSchedule []int64 `json:"DaysToSchedule"` 7 | Range struct { 8 | LowerDate string `json:"lowerDate"` 9 | UpperDate string `json:"upperDate"` 10 | } `json:"Range"` 11 | } `json:"DaysCfg"` 12 | DepartmentsID []int64 `json:"DepartmentsID"` 13 | EmployeesID []int64 `json:"EmployeesID"` 14 | EndDate string `json:"EndDate"` 15 | IntervalSize int64 `json:"IntervalSize"` 16 | IsActivitiesEnabled bool `json:"IsActivitiesEnabled"` 17 | ModifyExisting bool `json:"ModifyExisting"` 18 | OrignID int64 `json:"OrignId"` 19 | PrimaryOption int64 `json:"PrimaryOption"` 20 | ScheduleChanges []interface{} `json:"ScheduleChanges"` 21 | SchoolDays []interface{} `json:"SchoolDays"` 22 | StartDate string `json:"StartDate"` 23 | ZonesToSchedule []int64 `json:"ZonesToSchedule"` 24 | } 25 | -------------------------------------------------------------------------------- /imp_x2j.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2019-2023, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | 13 | xj "github.com/basgys/goxml2json" 14 | 15 | "github.com/go-easygen/go-flags/clis" 16 | ) 17 | 18 | //////////////////////////////////////////////////////////////////////////// 19 | // x2j 20 | 21 | // *** Sub-command: x2j *** 22 | // Exec implements the business logic of command `x2j` 23 | func (x *X2jCommand) Exec(args []string) error { 24 | fmt.Fprintf(os.Stderr, "%s v%s. x2j - XML to JSON\n", progname, version) 25 | // err := ... 26 | // clis.WarnOn("X2j, Exec", err) 27 | fileI := clis.GetInputStream(x.Filei) 28 | defer fileI.Close() 29 | fileO := clis.GetOutputStream(x.Fileo) 30 | defer fileO.Close() 31 | 32 | json, err := xj.Convert(fileI) 33 | clis.AbortOn("Convert from xml to json", err) 34 | 35 | fmt.Fprintln(fileO, json.String()) 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 go-jsonfile 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/Books.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Gambardella, Matthew 5 | XML Developer's Guide 6 | Computer 7 | 44.95 8 | 2000-10-01 9 | An in-depth look at creating applications 10 | with XML. 11 | 12 | 13 | Ralls, Kim 14 | Midnight Rain 15 | Fantasy 16 | 5.95 17 | 2000-12-16 18 | A former architect battles corporate zombies, 19 | an evil sorceress, and her own childhood to become queen 20 | of the world. 21 | 22 | 23 | Corets, Eva 24 | Maeve Ascendant 25 | Fantasy 26 | 5.95 27 | 2000-11-17 28 | After the collapse of a nanotechnology 29 | society in England, the young survivors lay the 30 | foundation for a new society. 31 | 32 | -------------------------------------------------------------------------------- /imp_sort.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2017-2023, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "encoding/json" 11 | "fmt" 12 | "io" 13 | 14 | "github.com/go-easygen/go-flags/clis" 15 | ) 16 | 17 | // *** Sub-command: sort *** 18 | // Exec implements the business logic of command `sort` 19 | func (x *SortCommand) Exec(args []string) error { 20 | fileI := clis.GetInputStream(x.Filei) 21 | defer fileI.Close() 22 | fileO := clis.GetOutputStream(x.Fileo) 23 | defer fileO.Close() 24 | 25 | return cmdSort(fileI, fileO) 26 | } 27 | 28 | //========================================================================== 29 | // support functions 30 | 31 | func cmdSort(r io.Reader, w io.Writer) error { 32 | var res interface{} 33 | content := readJson(r) 34 | json.Unmarshal(content, &res) 35 | var js []byte 36 | var err error 37 | if Opts.Compact { 38 | js, err = json.Marshal(res) 39 | } else { 40 | js, err = json.MarshalIndent(res, Opts.Prefix, Opts.Indent) 41 | } 42 | clis.AbortOn("[::sort] Marshaling input", err) 43 | fmt.Fprintln(w, string(js)) 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /test/SmartyStreetsCUC.json: -------------------------------------------------------------------------------- 1 | [{"InputIndex":0,"CandidateIndex":0,"DeliveryLine1":"1 N Rosedale St","LastLine":"Baltimore MD 21229-3737","DeliveryPointBarcode":"212293737013","Components":{"PrimaryNumber":"1","StreetPredirection":"N","StreetName":"Rosedale","StreetSuffix":"St","CityName":"Baltimore","StateAbbreviation":"MD","Zipcode":"21229","Plus4Code":"3737","DeliveryPoint":"01","DeliveryPointCheckDigit":"3"},"Metadata":{"RecordType":"S","ZipType":"Standard","CountyFips":"24510","CountyName":"Baltimore City","CarrierRoute":"C047","CongressionalDistrict":"07","Rdi":"Residential","ElotSequence":"0059","ElotSort":"A","Latitude":39.28602,"Longitude":-76.6689,"Precision":"Zip9","TimeZone":"Eastern","UtcOffset":-5,"Dst":true},"Analysis":{"DpvMatchCode":"Y","DpvFootnotes":"AABB","DpvCmra":"N","DpvVacant":"N","Active":"Y"}},{"InputIndex":0,"CandidateIndex":1,"DeliveryLine1":"1 S Rosedale St","LastLine":"Baltimore MD 21229-3739","DeliveryPointBarcode":"212293739011","Components":{"PrimaryNumber":"1","StreetPredirection":"S","StreetName":"Rosedale","StreetSuffix":"St","CityName":"Baltimore","StateAbbreviation":"MD","Zipcode":"21229","Plus4Code":"3739","DeliveryPoint":"01","DeliveryPointCheckDigit":"1"},"Metadata":{"RecordType":"S","ZipType":"Standard","CountyFips":"24510","CountyName":"Baltimore City","CarrierRoute":"C047","CongressionalDistrict":"07","Rdi":"Residential","ElotSequence":"0064","ElotSort":"A","Latitude":39.2858,"Longitude":-76.66889,"Precision":"Zip9","TimeZone":"Eastern","UtcOffset":-5,"Dst":true},"Analysis":{"DpvMatchCode":"Y","DpvFootnotes":"AABB","DpvCmra":"N","DpvVacant":"N","Active":"Y"}}] -------------------------------------------------------------------------------- /test/SmartyStreets.json: -------------------------------------------------------------------------------- 1 | [{"input_index":0,"candidate_index":0,"delivery_line_1":"1 N Rosedale St","last_line":"Baltimore MD 21229-3737","delivery_point_barcode":"212293737013","components":{"primary_number":"1","street_predirection":"N","street_name":"Rosedale","street_suffix":"St","city_name":"Baltimore","state_abbreviation":"MD","zipcode":"21229","plus4_code":"3737","delivery_point":"01","delivery_point_check_digit":"3"},"metadata":{"record_type":"S","zip_type":"Standard","county_fips":"24510","county_name":"Baltimore City","carrier_route":"C047","congressional_district":"07","rdi":"Residential","elot_sequence":"0059","elot_sort":"A","latitude":39.28602,"longitude":-76.6689,"precision":"Zip9","time_zone":"Eastern","utc_offset":-5,"dst":true},"analysis":{"dpv_match_code":"Y","dpv_footnotes":"AABB","dpv_cmra":"N","dpv_vacant":"N","active":"Y"}},{"input_index":0,"candidate_index":1,"delivery_line_1":"1 S Rosedale St","last_line":"Baltimore MD 21229-3739","delivery_point_barcode":"212293739011","components":{"primary_number":"1","street_predirection":"S","street_name":"Rosedale","street_suffix":"St","city_name":"Baltimore","state_abbreviation":"MD","zipcode":"21229","plus4_code":"3739","delivery_point":"01","delivery_point_check_digit":"1"},"metadata":{"record_type":"S","zip_type":"Standard","county_fips":"24510","county_name":"Baltimore City","carrier_route":"C047","congressional_district":"07","rdi":"Residential","elot_sequence":"0064","elot_sort":"A","latitude":39.2858,"longitude":-76.66889,"precision":"Zip9","time_zone":"Eastern","utc_offset":-5,"dst":true},"analysis":{"dpv_match_code":"Y","dpv_footnotes":"AABB","dpv_cmra":"N","dpv_vacant":"N","active":"Y"}}] -------------------------------------------------------------------------------- /test/SmartyStreetsCLK.json: -------------------------------------------------------------------------------- 1 | [{"input-index":0,"candidate-index":0,"delivery-line-1":"1 n rosedale st","last-line":"baltimore md 21229-3737","delivery-point-barcode":"212293737013","components":{"primary-number":"1","street-predirection":"n","street-name":"rosedale","street-suffix":"st","city-name":"baltimore","state-abbreviation":"md","zipcode":"21229","plus4-code":"3737","delivery-point":"01","delivery-point-check-digit":"3"},"metadata":{"record-type":"s","zip-type":"standard","county-fips":"24510","county-name":"baltimore city","carrier-route":"c047","congressional-district":"07","rdi":"residential","elot-sequence":"0059","elot-sort":"a","latitude":39.28602,"longitude":-76.6689,"precision":"zip9","time-zone":"eastern","utc-offset":-5,"dst":true},"analysis":{"dpv-match-code":"y","dpv-footnotes":"aabb","dpv-cmra":"n","dpv-vacant":"n","active":"y"}},{"input-index":0,"candidate-index":1,"delivery-line-1":"1 s rosedale st","last-line":"baltimore md 21229-3739","delivery-point-barcode":"212293739011","components":{"primary-number":"1","street-predirection":"s","street-name":"rosedale","street-suffix":"st","city-name":"baltimore","state-abbreviation":"md","zipcode":"21229","plus4-code":"3739","delivery-point":"01","delivery-point-check-digit":"1"},"metadata":{"record-type":"s","zip-type":"standard","county-fips":"24510","county-name":"baltimore city","carrier-route":"c047","congressional-district":"07","rdi":"residential","elot-sequence":"0064","elot-sort":"a","latitude":39.2858,"longitude":-76.66889,"precision":"zip9","time-zone":"eastern","utc-offset":-5,"dst":true},"analysis":{"dpv-match-code":"y","dpv-footnotes":"aabb","dpv-cmra":"n","dpv-vacant":"n","active":"y"}}] -------------------------------------------------------------------------------- /imp_fmt.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2017-2023, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "bytes" 11 | "encoding/json" 12 | "fmt" 13 | "regexp" 14 | "strconv" 15 | 16 | "github.com/go-easygen/go-flags/clis" 17 | ) 18 | 19 | // *** Sub-command: fmt *** 20 | // Exec implements the business logic of command `fmt` 21 | func (x *FmtCommand) Exec(args []string) error { 22 | fileI := clis.GetInputStream(x.Filei) 23 | defer fileI.Close() 24 | data := readJson(fileI) 25 | if x.Unescape { 26 | data = unescapeUnicode(data) 27 | } 28 | 29 | var out bytes.Buffer 30 | var err error 31 | if x.Concise { 32 | var formatted string 33 | formatted, err = FormatJSONMixed(data) 34 | out.WriteString(formatted) 35 | } else if Opts.Compact { 36 | err = json.Compact(&out, data) 37 | } else { 38 | err = json.Indent(&out, data, Opts.Prefix, Opts.Indent) 39 | } 40 | clis.AbortOn("Formatting input", err) 41 | fileO := clis.GetOutputStream(x.Fileo) 42 | defer fileO.Close() 43 | out.WriteTo(fileO) 44 | fmt.Fprintln(fileO) 45 | return nil 46 | } 47 | 48 | func unescapeUnicode(b []byte) []byte { 49 | // Unescape Unicode escape sequences like \u003c to actual characters 50 | re := regexp.MustCompile(`\\u[0-9a-fA-F]{4}`) 51 | return re.ReplaceAllFunc(b, func(match []byte) []byte { 52 | // Convert \uXXXX to actual character 53 | r, err := strconv.ParseInt(string(match[2:]), 16, 32) 54 | if err != nil { 55 | return match 56 | } 57 | return []byte(string(rune(r))) 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /imp_j2s.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2017-2023, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "path/filepath" 12 | 13 | "github.com/go-easygen/go-flags/clis" 14 | "github.com/go-jsonfile/gojson" 15 | "github.com/suntong/enum" 16 | ) 17 | 18 | //////////////////////////////////////////////////////////////////////////// 19 | // Global variables definitions 20 | 21 | var ( 22 | fmtTypeEn = enum.NewEnum() 23 | fmtJson = fmtTypeEn.Iota("json") 24 | fmtYaml = fmtTypeEn.Iota("yaml") 25 | 26 | gjparser = []gojson.Parser{gojson.ParseJson, gojson.ParseYaml} 27 | ) 28 | 29 | //////////////////////////////////////////////////////////////////////////// 30 | // Function definitions 31 | 32 | // *** Sub-command: j2s *** 33 | // Exec implements the business logic of command `j2s` 34 | func (x *J2sCommand) Exec(args []string) error { 35 | fmtType, ok := fmtTypeEn.Get(x.FmtType) 36 | if !ok { 37 | clis.AbortOn("Get FmtType", fmt.Errorf("Invalid format string: '%s'\n", x.FmtType)) 38 | } 39 | nameRoot := clis.Basename(filepath.Base(x.Filei)) 40 | if len(x.Name) != 0 { 41 | nameRoot = x.Name 42 | } 43 | 44 | fileI := clis.GetInputStream(x.Filei) 45 | defer fileI.Close() 46 | output, err := gojson.Generate(fileI, gjparser[fmtType], 47 | nameRoot, x.Pkg, []string{x.FmtType}, x.SubStruct) 48 | clis.AbortOn("Gojson Parsing", err) 49 | 50 | fileO := clis.GetOutputStream(x.Fileo) 51 | defer fileO.Close() 52 | fmt.Fprint(fileO, string(output)) 53 | // clis.WarnOn("J2s, Exec", err) 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /cmd_x2j.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2017-2023, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | 13 | "github.com/go-easygen/go-flags/clis" 14 | ) 15 | 16 | // *** Sub-command: x2j *** 17 | 18 | //////////////////////////////////////////////////////////////////////////// 19 | // Constant and data type/structure definitions 20 | 21 | // The X2jCommand type defines all the configurable options from cli. 22 | type X2jCommand struct { 23 | Filei string `short:"i" long:"input" description:"the source of the input JSON (mandatory)" required:"true"` 24 | Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 25 | } 26 | 27 | var x2jCommand X2jCommand 28 | 29 | //////////////////////////////////////////////////////////////////////////// 30 | // Function definitions 31 | 32 | func init() { 33 | gfParser.AddCommand("x2j", 34 | "XML to JSON", 35 | "", 36 | &x2jCommand) 37 | } 38 | 39 | func (x *X2jCommand) Execute(args []string) error { 40 | fmt.Fprintf(os.Stderr, "XML to JSON\n") 41 | // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2023, Tong Sun\n\n") 42 | clis.Setup("jsonfiddle::x2j", Opts.Verbose) 43 | clis.Verbose(1, "Doing X2j, with %+v, %+v", Opts, args) 44 | // fmt.Println(x.Filei, x.Fileo) 45 | return x.Exec(args) 46 | } 47 | 48 | // // Exec implements the business logic of command `x2j` 49 | // func (x *X2jCommand) Exec(args []string) error { 50 | // // err := ... 51 | // // clis.WarnOn("x2j::Exec", err) 52 | // // or, 53 | // // clis.AbortOn("x2j::Exec", err) 54 | // return nil 55 | // } 56 | -------------------------------------------------------------------------------- /cmd_esc.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2017-2023, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | 13 | "github.com/go-easygen/go-flags/clis" 14 | ) 15 | 16 | // *** Sub-command: esc *** 17 | 18 | //////////////////////////////////////////////////////////////////////////// 19 | // Constant and data type/structure definitions 20 | 21 | // The EscCommand type defines all the configurable options from cli. 22 | type EscCommand struct { 23 | Filei string `short:"i" long:"input" description:"the source to get json string from (or \"-\" for stdin) (mandatory)" required:"true"` 24 | Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 25 | } 26 | 27 | var escCommand EscCommand 28 | 29 | //////////////////////////////////////////////////////////////////////////// 30 | // Function definitions 31 | 32 | func init() { 33 | gfParser.AddCommand("esc", 34 | "Escape json string", 35 | "", 36 | &escCommand) 37 | } 38 | 39 | func (x *EscCommand) Execute(args []string) error { 40 | fmt.Fprintf(os.Stderr, "Escape json string\n") 41 | // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2023, Tong Sun\n\n") 42 | clis.Setup("jsonfiddle::esc", Opts.Verbose) 43 | clis.Verbose(1, "Doing Esc, with %+v, %+v", Opts, args) 44 | // fmt.Println(x.Filei, x.Fileo) 45 | return x.Exec(args) 46 | } 47 | 48 | // // Exec implements the business logic of command `esc` 49 | // func (x *EscCommand) Exec(args []string) error { 50 | // // err := ... 51 | // // clis.WarnOn("esc::Exec", err) 52 | // // or, 53 | // // clis.AbortOn("esc::Exec", err) 54 | // return nil 55 | // } 56 | -------------------------------------------------------------------------------- /cmd_sort.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2017-2023, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | 13 | "github.com/go-easygen/go-flags/clis" 14 | ) 15 | 16 | // *** Sub-command: sort *** 17 | 18 | //////////////////////////////////////////////////////////////////////////// 19 | // Constant and data type/structure definitions 20 | 21 | // The SortCommand type defines all the configurable options from cli. 22 | type SortCommand struct { 23 | Filei string `short:"i" long:"input" description:"the source to get json string from (mandatory)" required:"true"` 24 | Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 25 | } 26 | 27 | var sortCommand SortCommand 28 | 29 | //////////////////////////////////////////////////////////////////////////// 30 | // Function definitions 31 | 32 | func init() { 33 | gfParser.AddCommand("sort", 34 | "Sort json fields recursively", 35 | "", 36 | &sortCommand) 37 | } 38 | 39 | func (x *SortCommand) Execute(args []string) error { 40 | fmt.Fprintf(os.Stderr, "Sort json fields recursively\n") 41 | // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2023, Tong Sun\n\n") 42 | clis.Setup("jsonfiddle::sort", Opts.Verbose) 43 | clis.Verbose(1, "Doing Sort, with %+v, %+v", Opts, args) 44 | // fmt.Println(x.Filei, x.Fileo) 45 | return x.Exec(args) 46 | } 47 | 48 | // // Exec implements the business logic of command `sort` 49 | // func (x *SortCommand) Exec(args []string) error { 50 | // // err := ... 51 | // // clis.WarnOn("sort::Exec", err) 52 | // // or, 53 | // // clis.AbortOn("sort::Exec", err) 54 | // return nil 55 | // } 56 | -------------------------------------------------------------------------------- /cmd_fmt.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2017-2025, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | 13 | "github.com/go-easygen/go-flags/clis" 14 | ) 15 | 16 | // *** Sub-command: fmt *** 17 | 18 | //////////////////////////////////////////////////////////////////////////// 19 | // Constant and data type/structure definitions 20 | 21 | // The FmtCommand type defines all the configurable options from cli. 22 | type FmtCommand struct { 23 | Filei string `short:"i" long:"input" description:"the source to get json string from (mandatory)" required:"true"` 24 | Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 25 | Concise bool `short:"s" long:"concise" description:"Compact the top level array into concise array style"` 26 | Unescape bool `short:"u" long:"unescape" description:"Unescape unicode of form \u003c to their literal characters"` 27 | } 28 | 29 | var fmtCommand FmtCommand 30 | 31 | //////////////////////////////////////////////////////////////////////////// 32 | // Function definitions 33 | 34 | func init() { 35 | gfParser.AddCommand("fmt", 36 | "Format json string", 37 | ` 38 | `, 39 | &fmtCommand) 40 | } 41 | 42 | func (x *FmtCommand) Execute(args []string) error { 43 | fmt.Fprintf(os.Stderr, "Format json string\n") 44 | // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2025, Tong Sun\n\n") 45 | clis.Setup("jsonfiddle::fmt", Opts.Verbose) 46 | clis.Verbose(1, "Doing Fmt, with %+v, %+v", Opts, args) 47 | // fmt.Println(x.Filei, x.Fileo, x.Concise, x.Unescape) 48 | return x.Exec(args) 49 | } 50 | 51 | // // Exec implements the business logic of command `fmt` 52 | // func (x *FmtCommand) Exec(args []string) error { 53 | // // err := ... 54 | // // clis.WarnOn("fmt::Exec", err) 55 | // // or, 56 | // // clis.AbortOn("fmt::Exec", err) 57 | // return nil 58 | // } 59 | -------------------------------------------------------------------------------- /test/SmartyStreetsJ2S.ref: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type SmartyStreets []struct { 4 | Analysis struct { 5 | Active string `json:"active"` 6 | DpvCmra string `json:"dpv_cmra"` 7 | DpvFootnotes string `json:"dpv_footnotes"` 8 | DpvMatchCode string `json:"dpv_match_code"` 9 | DpvVacant string `json:"dpv_vacant"` 10 | } `json:"analysis"` 11 | CandidateIndex int64 `json:"candidate_index"` 12 | Components struct { 13 | CityName string `json:"city_name"` 14 | DeliveryPoint string `json:"delivery_point"` 15 | DeliveryPointCheckDigit string `json:"delivery_point_check_digit"` 16 | Plus4Code string `json:"plus4_code"` 17 | PrimaryNumber string `json:"primary_number"` 18 | StateAbbreviation string `json:"state_abbreviation"` 19 | StreetName string `json:"street_name"` 20 | StreetPredirection string `json:"street_predirection"` 21 | StreetSuffix string `json:"street_suffix"` 22 | Zipcode string `json:"zipcode"` 23 | } `json:"components"` 24 | DeliveryLine1 string `json:"delivery_line_1"` 25 | DeliveryPointBarcode string `json:"delivery_point_barcode"` 26 | InputIndex int64 `json:"input_index"` 27 | LastLine string `json:"last_line"` 28 | Metadata struct { 29 | CarrierRoute string `json:"carrier_route"` 30 | CongressionalDistrict string `json:"congressional_district"` 31 | CountyFips string `json:"county_fips"` 32 | CountyName string `json:"county_name"` 33 | Dst bool `json:"dst"` 34 | ElotSequence string `json:"elot_sequence"` 35 | ElotSort string `json:"elot_sort"` 36 | Latitude float64 `json:"latitude"` 37 | Longitude float64 `json:"longitude"` 38 | Precision string `json:"precision"` 39 | Rdi string `json:"rdi"` 40 | RecordType string `json:"record_type"` 41 | TimeZone string `json:"time_zone"` 42 | UtcOffset int64 `json:"utc_offset"` 43 | ZipType string `json:"zip_type"` 44 | } `json:"metadata"` 45 | } 46 | -------------------------------------------------------------------------------- /cmd_j2s.go: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Program: jsonfiddle 3 | // Purpose: JSON Fiddling 4 | // Authors: Tong Sun (c) 2017-2023, All rights reserved 5 | //////////////////////////////////////////////////////////////////////////// 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | 13 | "github.com/go-easygen/go-flags/clis" 14 | ) 15 | 16 | // *** Sub-command: j2s *** 17 | 18 | //////////////////////////////////////////////////////////////////////////// 19 | // Constant and data type/structure definitions 20 | 21 | // The J2sCommand type defines all the configurable options from cli. 22 | type J2sCommand struct { 23 | FmtType string `short:"f" long:"fmt" description:"the structural format of the input data (json/yaml)" default:"json"` 24 | Filei string `short:"i" long:"input" description:"the source of the input JSON (mandatory)" required:"true"` 25 | Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 26 | Name string `long:"name" description:"the name of the root struct (default: as input file name)"` 27 | Pkg string `long:"pkg" description:"the name of the package for the generated code" default:"main"` 28 | SubStruct bool `long:"subStruct" description:"create types for sub-structs"` 29 | } 30 | 31 | var j2sCommand J2sCommand 32 | 33 | //////////////////////////////////////////////////////////////////////////// 34 | // Function definitions 35 | 36 | func init() { 37 | gfParser.AddCommand("j2s", 38 | "JSON to struct", 39 | "JSON convert to Go struct", 40 | &j2sCommand) 41 | } 42 | 43 | func (x *J2sCommand) Execute(args []string) error { 44 | fmt.Fprintf(os.Stderr, "JSON to struct\n") 45 | // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2023, Tong Sun\n\n") 46 | clis.Setup("jsonfiddle::j2s", Opts.Verbose) 47 | clis.Verbose(1, "Doing J2s, with %+v, %+v", Opts, args) 48 | // fmt.Println(x.FmtType, x.Filei, x.Fileo, x.Name, x.Pkg, x.SubStruct) 49 | return x.Exec(args) 50 | } 51 | 52 | // // Exec implements the business logic of command `j2s` 53 | // func (x *J2sCommand) Exec(args []string) error { 54 | // // err := ... 55 | // // clis.WarnOn("j2s::Exec", err) 56 | // // or, 57 | // // clis.AbortOn("j2s::Exec", err) 58 | // return nil 59 | // } 60 | -------------------------------------------------------------------------------- /prop_fmt_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // NOTE: The FormatJSONMixed function and the Element/Root structs 8 | // are assumed to be in a file named 'json_formatter.go' in the same directory. 9 | 10 | // Test data used for the Object-Wrapped Array case 11 | type testObjectData struct { 12 | Users []struct { 13 | ID int `json:"id"` 14 | Active bool `json:"active"` 15 | } `json:"users"` 16 | } 17 | 18 | // Test data used for the Pure Array case 19 | type testArrayData []struct { 20 | Name string `json:"name"` 21 | City string `json:"city"` 22 | } 23 | 24 | func TestFormatJSONMixed_Object(t *testing.T) { 25 | // GIVEN a structured Go object that will serialize to {"key": [elements]} 26 | testData := testObjectData{ 27 | Users: []struct { 28 | ID int `json:"id"` 29 | Active bool `json:"active"` 30 | }{ 31 | {ID: 1, Active: true}, 32 | {ID: 2, Active: false}, 33 | }, 34 | } 35 | 36 | // The expected output for this structure 37 | expected := `{ "users": [ 38 | {"active":true,"id":1}, 39 | {"active":false,"id":2} 40 | ] 41 | }` 42 | 43 | // WHEN the formatting function is called 44 | formatted, err := FormatJSONMixed(testData) 45 | 46 | // THEN it should format correctly without error 47 | if err != nil { 48 | t.Fatalf("FormatJSONMixed failed with error: %v", err) 49 | } 50 | 51 | if formatted != expected { 52 | t.Errorf("Object Test Failed.\nExpected:\n%s\nGot:\n%s", expected, formatted) 53 | } 54 | } 55 | 56 | func TestFormatJSONMixed_Array(t *testing.T) { 57 | // GIVEN a structured Go array that will serialize to [elements] 58 | testData := testArrayData{ 59 | {Name: "Alice", City: "NYC"}, 60 | {Name: "Bob", City: "LA"}, 61 | {Name: "Charlie", City: "SF"}, 62 | } 63 | 64 | // The expected output for this structure 65 | expected := `[ 66 | {"city":"NYC","name":"Alice"}, 67 | {"city":"LA","name":"Bob"}, 68 | {"city":"SF","name":"Charlie"} 69 | ]` 70 | 71 | // WHEN the formatting function is called 72 | formatted, err := FormatJSONMixed(testData) 73 | 74 | // THEN it should format correctly without error 75 | if err != nil { 76 | t.Fatalf("FormatJSONMixed failed with error: %v", err) 77 | } 78 | 79 | if formatted != expected { 80 | t.Errorf("Array Test Failed.\nExpected:\n%s\nGot:\n%s", expected, formatted) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /jsonfiddle_main.go: -------------------------------------------------------------------------------- 1 | // jsonfiddle - JSON Fiddling 2 | 3 | // Tool to fiddle with json strings 4 | 5 | package main 6 | 7 | //////////////////////////////////////////////////////////////////////////// 8 | // Program: jsonfiddle 9 | // Purpose: JSON Fiddling 10 | // Authors: Tong Sun (c) 2017-2025, All rights reserved 11 | //////////////////////////////////////////////////////////////////////////// 12 | 13 | //go:generate sh jsonfiddle_cliGen.sh 14 | //go:generate emd gen -in README.e.md -out README.md 15 | 16 | import ( 17 | "fmt" 18 | "io" 19 | "os" 20 | "regexp" 21 | 22 | "github.com/go-easygen/go-flags" 23 | "github.com/go-easygen/go-flags/clis" 24 | ) 25 | 26 | ////////////////////////////////////////////////////////////////////////// 27 | // Constant and data type/structure definitions 28 | 29 | //////////////////////////////////////////////////////////////////////////// 30 | // Global variables definitions 31 | 32 | var ( 33 | progname = "jsonfiddle" 34 | version = "0.6.0" 35 | date = "2025-11-18" 36 | 37 | // Opts store all the configurable options 38 | Opts OptsT 39 | ) 40 | 41 | var gfParser = flags.NewParser(&Opts, flags.Default) 42 | 43 | //////////////////////////////////////////////////////////////////////////// 44 | // Function definitions 45 | 46 | // ========================================================================== 47 | // Function main 48 | func main() { 49 | Opts.Version = showVersion 50 | Opts.Verbflg = func() { 51 | Opts.Verbose++ 52 | } 53 | 54 | if _, err := gfParser.Parse(); err != nil { 55 | fmt.Println() 56 | gfParser.WriteHelp(os.Stdout) 57 | os.Exit(1) 58 | } 59 | fmt.Println() 60 | //DoJsonfiddle() 61 | } 62 | 63 | //========================================================================== 64 | // support functions 65 | 66 | func showVersion() { 67 | fmt.Fprintf(os.Stderr, "jsonfiddle - JSON Fiddling, version %s\n", version) 68 | fmt.Fprintf(os.Stderr, "Built on %s\n", date) 69 | fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2025, Tong Sun\n\n") 70 | fmt.Fprintf(os.Stderr, "Tool to fiddle with json strings\n") 71 | os.Exit(0) 72 | } 73 | 74 | // readJson reads the given json file as []byte. 75 | func readJson(r io.Reader) []byte { 76 | data, err := io.ReadAll(r) 77 | clis.AbortOn("Reading json input", err) 78 | 79 | if Opts.Protect { 80 | data = regexp.MustCompile(`({{)([^ }]+)(}})`). 81 | ReplaceAll(data, []byte(`<<${2}>>`)) 82 | // "age":<> => "age":"<>" 83 | data = regexp.MustCompile(`(:)(<<[^>]+>>)([]},])`). 84 | ReplaceAll(data, []byte(`${1}"${2}"${3}`)) 85 | } 86 | clis.Verbose(2, "%s", string(data)) 87 | return data 88 | } 89 | -------------------------------------------------------------------------------- /.github/workflows/go-release-build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | tags: 8 | - 'v*' 9 | pull_request: 10 | # Allows you to run this workflow manually from the Actions tab 11 | workflow_dispatch: 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - 18 | name: Checkout 19 | uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | - 23 | name: Set up Go 24 | uses: actions/setup-go@v5 25 | with: 26 | go-version: 1.23.1 27 | 28 | - 29 | name: Cache Go modules 30 | uses: actions/cache@v4 31 | # Do before go get 32 | with: 33 | path: ~/go/pkg/mod 34 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 35 | restore-keys: | 36 | ${{ runner.os }}-go- 37 | 38 | - 39 | name: Tests 40 | run: | 41 | go mod tidy 42 | go build -v -trimpath 43 | go test -v ./... 44 | 45 | - 46 | name: Run GoReleaser 47 | uses: goreleaser/goreleaser-action@v5 48 | if: success() && startsWith(github.ref, 'refs/tags/') 49 | with: 50 | version: latest 51 | args: release --clean 52 | env: 53 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 54 | 55 | - 56 | name: Install Cloudsmith CLI 57 | if: success() && startsWith(github.ref, 'refs/tags/') 58 | run: pip install --upgrade cloudsmith-cli 59 | # Cloudsmith CLI tooling for pushing releases 60 | # See https://help.cloudsmith.io/docs/cli 61 | 62 | # Publish to cloudsmith repo 63 | - 64 | name: Publish package to cloudsmith 65 | if: success() && startsWith(github.ref, 'refs/tags/') 66 | env: 67 | CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }} 68 | run: | 69 | for filepath in dist/*; do 70 | echo "== Analyzing '$filepath' for publishing" 71 | filename=$(basename -- "$filepath") 72 | extension="${filename##*.}" 73 | filename="${filename%.*}" 74 | case "$extension" in 75 | 'apk') 76 | echo "Pushing '$filepath' to cloudsmith repo" 77 | cloudsmith push alpine suntong/repo/alpine/any-version $filepath 78 | ;; 79 | 'deb' | 'rpm') 80 | echo "Pushing '$filepath' to cloudsmith repo" 81 | cloudsmith push $extension suntong/repo/any-distro/any-version $filepath 82 | ;; 83 | *) 84 | echo "File .$extension skipped publishing" 85 | echo 86 | ;; 87 | esac 88 | done 89 | -------------------------------------------------------------------------------- /jsonfiddle_test.go: -------------------------------------------------------------------------------- 1 | package main_test 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | "os/exec" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | const ( 12 | cmdTest = "../jsonfiddle" 13 | dirTest = "test/" 14 | extRef = ".ref" // extension for reference file 15 | extGot = ".got" // extension for generated file 16 | ) 17 | 18 | // testIt runs @cmdEasyGen with @argv and compares the generated 19 | // output for @name with the corresponding @extRef 20 | func testIt(t *testing.T, name string, argv ...string) { 21 | var ( 22 | diffOut bytes.Buffer 23 | generatedOutput = name + extGot 24 | cmd = exec.Command(cmdTest, argv...) 25 | ) 26 | 27 | t.Logf("Testing %s:\n\t%s %s\n", name, cmdTest, strings.Join(argv, " ")) 28 | 29 | // open the out file for writing 30 | outfile, err := os.Create(generatedOutput) 31 | if err != nil { 32 | t.Errorf("write error [%s: %s] %s.", name, argv, err) 33 | } 34 | defer outfile.Close() 35 | cmd.Stdout = outfile 36 | 37 | err = cmd.Start() 38 | if err != nil { 39 | t.Errorf("start error [%s: %s] %s.", name, argv, err) 40 | } 41 | err = cmd.Wait() 42 | if err != nil { 43 | t.Errorf("exit error [%s: %s] %s.", name, argv, err) 44 | } 45 | 46 | cmd = exec.Command("diff", "-U1", name+extRef, generatedOutput) 47 | cmd.Stdout = &diffOut 48 | 49 | err = cmd.Start() 50 | if err != nil { 51 | t.Errorf("start error %s [%s: %s]", err, name, argv) 52 | } 53 | err = cmd.Wait() 54 | if err != nil { 55 | t.Errorf("cmp error %s [%s: %s]\n%s", err, name, argv, diffOut.String()) 56 | } 57 | //os.Remove(generatedOutput) 58 | } 59 | 60 | func TestExec(t *testing.T) { 61 | os.Chdir(dirTest) 62 | 63 | // == Test Basic Functions 64 | // -- fmt 65 | t.Logf("\n\n== Testing Basic fmt Functions\n\n") 66 | testIt(t, "CustomerC", "fmt", "-c", "-i", "Customer.json") 67 | testIt(t, "Customer", "fmt", "-i", "Customer.json") 68 | testIt(t, "Schedules", "fmt", "-i", "Schedules.json") 69 | testIt(t, "CustomerP", "fmt", "-p", "-i", "CustomerP.json") 70 | testIt(t, "CustomerPC", "fmt", "-c", "-p", "-i", "CustomerP.json") 71 | testIt(t, "FmtConciseO", "fmt", "-s", "-i", "FmtConciseO.json") 72 | testIt(t, "FmtConciseA", "fmt", "--concise", "-i", "FmtConciseA.json") 73 | // -- sort 74 | t.Logf("\n\n== Testing Basic sort Functions\n\n") 75 | testIt(t, "CustomerSI", "sort", "-i", "Customer.json") 76 | testIt(t, "CustomerSC", "sort", "-c", "-i", "Customer.json") 77 | testIt(t, "CustomerPS", "sort", "-p", "-i", "CustomerP.json") 78 | testIt(t, "SchedulesSI", "sort", "-i", "Schedules.json") 79 | // -- j2s 80 | t.Logf("\n\n== Testing Basic j2s Functions\n\n") 81 | testIt(t, "CustomerJ2S", "j2s", "-i", "Customer.json") 82 | testIt(t, "GoodsJ2S", "j2s", "-i", "Goods.json") 83 | testIt(t, "MenuItemsJ2S", "j2s", "-i", "MenuItems.json") 84 | testIt(t, "SmartyStreetsJ2S", "j2s", "-i", "SmartyStreets.json") 85 | testIt(t, "SchedulesJ2S", "j2s", "-i", "Schedules.json") 86 | // -- x2j 87 | //t.Logf("\n\n== Testing Basic x2j Functions\n\n") 88 | //testIt(t, "Books", "x2j", "-i", "Books.xml") 89 | } 90 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/basgys/goxml2json v1.1.0 h1:4ln5i4rseYfXNd86lGEB+Vi652IsIXIvggKM/BhUKVw= 2 | github.com/basgys/goxml2json v1.1.0/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw= 3 | github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow= 4 | github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q= 5 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 6 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/go-easygen/go-flags v1.5.3 h1:e9axNakjTs/7XplQYxKdNOzaEBBZE87CKT7AMr8tAt8= 8 | github.com/go-easygen/go-flags v1.5.3/go.mod h1:9XapqeN/a8SC8mcfSFx0mqJtclk/jmdHPSG0GFG28v4= 9 | github.com/go-jsonfile/gojson v0.0.0-20170804141630-ca37eb6137fb h1:tK9Elt90UI3w2vpw+X1Q+b+uDBJyFh9S+P7Vpv15jKQ= 10 | github.com/go-jsonfile/gojson v0.0.0-20170804141630-ca37eb6137fb/go.mod h1:le1R/RmJZoUEfw2CqP+AJRATTefVWNRho6+LpCv3RfA= 11 | github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= 12 | github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= 13 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 14 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 15 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 16 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 17 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 18 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 19 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 20 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 21 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 22 | github.com/suntong/enum v2.0.1+incompatible h1:FhkYIWbi9v3P1ngGi1ot624IomUxDi8qg16V5ckSix8= 23 | github.com/suntong/enum v2.0.1+incompatible/go.mod h1:5C9SCEyLWDsCY6OP6Mdf9Fquw60jiWWRxz1Wbo67ADQ= 24 | golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= 25 | golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= 26 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 27 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 28 | golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= 29 | golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 30 | golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= 31 | golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= 32 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 33 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 34 | gopkg.in/suntong/enum.v1 v1.0.0 h1:kxqQtdsRYfrrbNcMnNd7tNhNL7sdKilDSPpWRQgweWE= 35 | gopkg.in/suntong/enum.v1 v1.0.0/go.mod h1:58a1R4P3MwCu/Ub0+ihobgrjzPZlhB1kbU3lvD+Cf4U= 36 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 37 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 38 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 39 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 40 | -------------------------------------------------------------------------------- /prop_fmt.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "strings" 8 | ) 9 | 10 | // FormatJSONMixed handles two top-level JSON structures: 11 | // 1. A single-key object containing an array: {"key": [elements]} 12 | // 2. A pure array of objects: [elements] 13 | // It formats the output with compact, single-line array elements. 14 | func FormatJSONMixed(input interface{}) (string, error) { 15 | var rawJSON []byte 16 | var err error 17 | 18 | // 1. Ensure we have raw JSON bytes to work with. 19 | switch v := input.(type) { 20 | case []byte: 21 | rawJSON = v 22 | case string: 23 | rawJSON = []byte(v) 24 | default: 25 | rawJSON, err = json.Marshal(v) 26 | if err != nil { 27 | return "", fmt.Errorf("failed to marshal input: %v", err) 28 | } 29 | } 30 | 31 | // 2. Unmarshal into a generic interface{} to check its type. 32 | var genericData interface{} 33 | if err := json.Unmarshal(rawJSON, &genericData); err != nil { 34 | return "", fmt.Errorf("failed to unmarshal JSON: %v", err) 35 | } 36 | 37 | var sb strings.Builder 38 | 39 | // Determine the array source based on the top-level structure 40 | switch v := genericData.(type) { 41 | case map[string]interface{}: 42 | // --- Case 1: Root is a single-key object --- 43 | 44 | // Validation check ensures only one key exists 45 | if len(v) != 1 { 46 | return "", fmt.Errorf("input JSON object must have exactly one root key, found %d", len(v)) 47 | } 48 | 49 | sb.WriteString("{ ") 50 | 51 | // Use a composite loop/assignment to get the single key/value pair 52 | // because Go maps are unordered and cannot be accessed by index or 53 | // a known key without knowing the key name first 54 | var key string 55 | var value interface{} 56 | for k, val := range v { 57 | key = k 58 | value = val 59 | break // geet the 1st (and only) pair, see earlier strong validation check 60 | } 61 | 62 | // Validate the value is an array (slice) 63 | elementArray, ok := value.([]interface{}) 64 | if !ok { 65 | return "", fmt.Errorf("value for key %q is not a JSON array", key) 66 | } 67 | 68 | keyBytes, _ := json.Marshal(key) 69 | // Write the indented key and array start 70 | //sb.WriteString(" ") // 2-space indent 71 | sb.Write(keyBytes) 72 | sb.WriteString(": [\n") 73 | 74 | // Format the elements 75 | if err := formatArrayElements(&sb, elementArray, 4); err != nil { 76 | return "", err 77 | } 78 | 79 | // Write the closing array and object 80 | sb.WriteString(" ]\n") 81 | sb.WriteString("}") 82 | 83 | case []interface{}: 84 | // --- Case 2: Root is a pure array --- 85 | 86 | sb.WriteString("[\n") 87 | 88 | // Format the elements 89 | if err := formatArrayElements(&sb, v, 2); err != nil { 90 | return "", err 91 | } 92 | 93 | // Write the closing array bracket 94 | sb.WriteString("]") 95 | 96 | default: 97 | return "", fmt.Errorf("unsupported root JSON structure. Must be an array object or an array") 98 | } 99 | 100 | return sb.String(), nil 101 | } 102 | 103 | // formatArrayElements contains the core logic for marshalling and indenting elements. 104 | func formatArrayElements(sb *strings.Builder, elements []interface{}, indentSpaces int) error { 105 | indent := strings.Repeat(" ", indentSpaces) 106 | numElements := len(elements) 107 | 108 | for i, element := range elements { 109 | // Marshal the single element (compact, one-line string) 110 | elemBytes, err := json.Marshal(element) 111 | if err != nil { 112 | return fmt.Errorf("failed to marshal element %d: %v", i, err) 113 | } 114 | 115 | // Write the indented element 116 | sb.WriteString(indent) 117 | sb.Write(elemBytes) 118 | 119 | // Add comma and newline 120 | if i < numElements-1 { 121 | sb.WriteString(",") 122 | } 123 | sb.WriteString("\n") 124 | } 125 | log.Println(numElements, "elements.") 126 | return nil 127 | } 128 | -------------------------------------------------------------------------------- /jsonfiddle_cli.yaml: -------------------------------------------------------------------------------- 1 | # GoFlags based cli def file 2 | 3 | # program name, name for the executable 4 | ProgramName: jsonfiddle 5 | Authors: Tong Sun 6 | Since: 2017 7 | 8 | PackageName: main 9 | 10 | Name: jsonfiddle 11 | Desc: "JSON Fiddling" 12 | Text: Tool to fiddle with json strings 13 | Verbose: true 14 | Version: true 15 | 16 | #UsageLead: "Usage:\\n jsonfiddle [Options] dir [dirs...]" 17 | 18 | Options: 19 | 20 | - Name: Compact 21 | Type: bool 22 | Flag: 'c,compact' 23 | Usage: Compact JSON data, remove all whitespaces 24 | 25 | - Name: Prefix 26 | Type: string 27 | Flag: 'prefix' 28 | Usage: prefix for json string output 29 | Value: '' 30 | 31 | - Name: Indent 32 | Type: string 33 | Flag: 'd,indent' 34 | Usage: indent for json string output 35 | Value: ' ' 36 | 37 | - Name: Protect 38 | Type: bool 39 | Flag: p,protect 40 | Usage: protect {{TEMPLATE}} in JSON data 41 | 42 | Command: 43 | 44 | - Name: esc 45 | Desc: "Escape json string" 46 | Text: '' 47 | #Text: 'Usage:\n jsonfiddle esc [Options]' 48 | 49 | Options: 50 | - Name: Filei 51 | Type: string 52 | Required: true 53 | Flag: 'i,input' 54 | Usage: 'the source to get json string from (or \"-\" for stdin) (mandatory)' 55 | 56 | - Name: Fileo 57 | Type: string 58 | Flag: o,output 59 | Value: "-" 60 | Usage: 'the output, default to stdout' 61 | 62 | - Name: fmt 63 | Desc: "Format json string" 64 | Text: '' 65 | #Text: 'Usage:\n jsonfiddle fmt [Options]' 66 | 67 | Options: 68 | - Name: Filei 69 | Type: string 70 | Required: true 71 | Flag: 'i,input' 72 | Usage: the source to get json string from (mandatory) 73 | 74 | - Name: Fileo 75 | Type: string 76 | Flag: o,output 77 | Value: "-" 78 | Usage: 'the output, default to stdout' 79 | 80 | - Name: Concise 81 | Type: bool 82 | Flag: 's,concise' 83 | Usage: "Compact the top level array into concise array style" 84 | 85 | - Name: Unescape 86 | Type: bool 87 | Flag: 'u,unescape' 88 | Usage: "Unescape unicode of form \\u003c to their literal characters" 89 | 90 | - Name: sort 91 | Desc: "Sort json fields recursively" 92 | Text: '' 93 | #Text: 'Usage:\n jsonfiddle sort [Options]' 94 | 95 | Options: 96 | - Name: Filei 97 | Type: string 98 | Required: true 99 | Flag: 'i,input' 100 | Usage: the source to get json string from (mandatory) 101 | 102 | - Name: Fileo 103 | Type: string 104 | Flag: o,output 105 | Value: "-" 106 | Usage: 'the output, default to stdout' 107 | 108 | - Name: j2s 109 | Desc: "JSON to struct" 110 | Text: 'JSON convert to Go struct' 111 | #Text: 'Usage:\n jsonfiddle j2s [Options]' 112 | 113 | Options: 114 | 115 | - Name: FmtType 116 | Type: string 117 | Flag: f,fmt 118 | Usage: the structural format of the input data (json/yaml) 119 | Value: json 120 | 121 | - Name: Filei 122 | Type: string 123 | Required: true 124 | Flag: 'i,input' 125 | Usage: the source of the input JSON (mandatory) 126 | 127 | - Name: Fileo 128 | Type: string 129 | Flag: o,output 130 | Value: "-" 131 | Usage: 'the output, default to stdout' 132 | 133 | - Name: Name 134 | Type: string 135 | Flag: name 136 | Usage: 'the name of the root struct (default: as input file name)' 137 | 138 | - Name: Pkg 139 | Type: string 140 | Flag: pkg 141 | Usage: the name of the package for the generated code 142 | Value: main 143 | 144 | - Name: SubStruct 145 | Type: bool 146 | Flag: subStruct 147 | Usage: create types for sub-structs 148 | 149 | # - Name: tags 150 | # Type: string 151 | # Flag: tags 152 | # Usage: comma seperated list of the tags to put on the struct, default is the same as fmt 153 | # Value: fmt 154 | 155 | # - Name: ForceFloats 156 | # Type: bool 157 | # Flag: forcefloats 158 | # Usage: [experimental] force float64 type for integral values 159 | 160 | - Name: x2j 161 | Desc: "XML to JSON" 162 | Text: '' 163 | 164 | Options: 165 | 166 | - Name: Filei 167 | Type: string 168 | Required: true 169 | Flag: 'i,input' 170 | Usage: the source of the input JSON (mandatory) 171 | 172 | - Name: Fileo 173 | Type: string 174 | Flag: o,output 175 | Value: "-" 176 | Usage: 'the output, default to stdout' 177 | 178 | -------------------------------------------------------------------------------- /README.e.md: -------------------------------------------------------------------------------- 1 | 2 | # {{.Name}} 3 | 4 | {{render "license/shields" . "License" "MIT"}} 5 | {{template "badge/godoc" .}} 6 | {{template "badge/goreport" .}} 7 | {{template "badge/travis" .}} 8 | [![PoweredBy WireFrame](https://github.com/go-easygen/wireframe/blob/master/PoweredBy-WireFrame-R.svg)](http://godoc.org/github.com/go-easygen/wireframe) 9 | 10 | ## {{toc 5}} 11 | 12 | ## {{.Name}} - JSON Fiddling 13 | 14 | The `jsonfiddle` makes it easy to look at the JSON data from different aspects. 15 | 16 | - **`jsonfiddle esc`** will escape any arbitrary string so as to embed it as content of json string. 17 | - **`jsonfiddle fmt`** will format the JSON data, either compact it or pretty printing it. The order of fields are intact. 18 | - **`jsonfiddle sort`** will sort the JSON data fields recursively, so that the attributes at any level are in sorted order. 19 | - **`jsonfiddle x2j`** means xml to json. It will convert data from xml format into json. 20 | - **`jsonfiddle j2s`** means json to struct. It will extract the structure of JSON data as Go struct. 21 | 22 | # Usage 23 | 24 | ``` 25 | $ {{shell "jsonfiddle -V"}} 26 | ``` 27 | 28 | ### $ {{shell "jsonfiddle || true" | color "sh"}} 29 | 30 | ### $ {{shell "jsonfiddle esc || true" | color "sh"}} 31 | 32 | ### $ {{shell "jsonfiddle fmt || true" | color "sh"}} 33 | 34 | ### $ {{shell "jsonfiddle sort || true" | color "sh"}} 35 | 36 | ### $ {{shell "jsonfiddle j2s || true" | color "sh"}} 37 | 38 | ### $ {{shell "jsonfiddle x2j || true" | color "sh"}} 39 | 40 | # Examples 41 | 42 | ## Escape with `jsonfiddle esc` 43 | 44 | ### $ {{shell "jsonfiddle esc -i test/Customer.ref 2>/dev/null" | color "json"}} 45 | 46 | ### Usage 47 | 48 | `jsonfiddle esc` will escape any arbitrary string so as to embed it as content of json string. This seems useless at first, but it actually allows you to embed any arbitrary file into [GitHub Gists JSON API](https://developer.github.com/v3/gists/), so as to post any arbitrary file onto GitHub Gist: 49 | 50 | 51 | echo '{"description":"SmartyStreets API Demo","public":true,"files":{"SmartyStreets.json":{"content":'"`jsonfiddle fmt -i test/SmartyStreets.json | jsonfiddle esc -i`"'}}}' | curl --data @- https://api.github.com/gists 52 | 53 | This will give you 54 | https://gist.github.com/anonymous/1423d4768dd9b88262ca513626e68d8e 55 | 56 | 57 | By "_arbitrary file_" I do mean arbitrary file. Check this out: 58 | https://gist.github.com/anonymous/a51798ce99ff59d8d4ba536cbf4b6996 59 | 60 | This is why `jsonfiddle esc` is a command on its own, instead of being part of functionalities of `jsonfiddle fmt` or `jsonfiddle sort`. 61 | 62 | ## Format with `jsonfiddle fmt` 63 | 64 | ### Pretty print 65 | 66 | $ jsonfiddle fmt -i test/Customer.json 67 | 68 | #### > {{cat "test/CustomerSI.ref" | color "json"}} 69 | 70 | ### Protect templates in json data 71 | 72 | There are times that json data may contain templates, i.e., strings like `{{"{{VARIABLE}}"}}`. Some of the pretty printing tools, like the json plugin in Notepad++, cannot handle such template forms well, and will turn `{{"{{VARIABLE}}"}}` into: 73 | 74 | ```json 75 | { 76 | { 77 | VARIABLE 78 | } 79 | } 80 | ``` 81 | 82 | What's worse is that when such template variables are for `int`, e.g.: `"age":{{"{{Var_Age}}"}}`, they then wouldn't be able to handle it, for inputs like 83 | {{cat "test/CustomerP.json" | color "sh"}} 84 | 85 | To make such template variables work for those tools, the `-p,--protect` option is introduced: 86 | 87 | $ jsonfiddle fmt -p -i test/CustomerP.json 88 | 89 | #### > {{cat "test/CustomerP.ref" | color "json"}} 90 | 91 | ### Compact 92 | 93 | $ jsonfiddle fmt -c -i test/Customer.json 94 | 95 | #### > {{cat "test/CustomerC.ref" | color "json"}} 96 | 97 | You can also do, 98 | 99 | $ cat Customer.json | jsonfiddle fmt -c -i - 100 | 101 | and the result is the same (and for all other examples using `-i` as well). 102 | 103 | ## Sort fields with `jsonfiddle sort` 104 | 105 | ### Sort in compact 106 | 107 | $ jsonfiddle sort -c -i test/Customer.json 108 | 109 | #### > {{cat "test/CustomerSC.ref" | color "json"}} 110 | 111 | ### Sort with pretty print 112 | 113 | $ jsonfiddle sort -i test/Customer.json 114 | 115 | #### > {{cat "test/CustomerSI.ref" | color "json"}} 116 | 117 | ### XML to JSON, sort then pretty print 118 | 119 | ``` 120 | $ {{shell "jsonfiddle x2j -i test/Books.xml | jsonfiddle sort -i - | jsonfiddle fmt -i -"}} 121 | ``` 122 | 123 | ## JSON to struct via `jsonfiddle j2s` 124 | 125 | $ jsonfiddle j2s -i test/Customer.json 126 | 127 | #### > {{cat "test/CustomerJ2S.ref" | color "go"}} 128 | 129 | 130 | # Purpose 131 | 132 | A few more words on why I'm writing the tool -- because I need to compare JSON string that are roughly close and very complicated in the mean time -- sometimes even less than 30% of fields are the same, of course, this is after their having been sorted, otherwise, it'd be 100% different. 133 | 134 | Thus all the JSON comparison tools I found are failing under such hash request. So far, I personally find that 135 | 136 | - Sorting the JSON data fields recursively and producing plain text file (via `jsonfiddle sort`), then use the state-of-the-art text comparison tools to compare them is the best approach, for my above scenario. 137 | - For extremely long and very complicated JSONs, converting json to abstract Go struct (via `jsonfiddle j2s`) is the quickest approach to compare them at higher level. 138 | 139 | # Download binaries 140 | 141 | - The latest binary executables are available under 142 | https://github.com/go-jsonfile/{{.Name}}/releases 143 | as the result of the Continuous-Integration process. 144 | - I.e., they are built right from the source code during every git tagging commit automatically. 145 | - Pick & choose the binary executable that suits your OS and its architecture. E.g., for Linux, it would most probably be the `{{.Name}}_linux_VER_amd64` file. If your OS and its architecture is not available in the download list, please let me know and I'll add it. 146 | - You may want to rename it to a shorter name instead, e.g., `{{.Name}}`, after downloading it. 147 | 148 | 149 | # Debian package 150 | 151 | Available at the above releases url as well. 152 | 153 | # Install Source 154 | 155 | To install the source code instead: 156 | 157 | ``` 158 | go get github.com/go-jsonfile/jsonfiddle 159 | ``` 160 | 161 | 162 | ## Credits 163 | 164 | - [Ladicle/gojson](https://github.com/Ladicle/gojson) forked source for JSON to struct 165 | - [ChimeraCoder/gojson](https://github.com/ChimeraCoder/gojson) the original source of [Ladicle/gojson](https://github.com/Ladicle/gojson). 166 | 167 | ## Similar Projects 168 | 169 | All the following similar projects have been considered before writing one on my own instead. 170 | 171 | . . . to be filled . . . 172 | 173 | ## Author(s) & Contributor(s) 174 | 175 | Tong SUN 176 | ![suntong from cpan.org](https://img.shields.io/badge/suntong-%40cpan.org-lightgrey.svg "suntong from cpan.org") 177 | 178 | _Powered by_ [**WireFrame**](https://github.com/go-easygen/wireframe), [![PoweredBy WireFrame](https://github.com/go-easygen/wireframe/blob/master/PoweredBy-WireFrame-Y.svg)](http://godoc.org/github.com/go-easygen/wireframe), the _one-stop wire-framing solution_ for Go cli based projects, from start to deploy. 179 | 180 | All patches welcome. 181 | -------------------------------------------------------------------------------- /jsonfiddle_cliDef.go: -------------------------------------------------------------------------------- 1 | // jsonfiddle - JSON Fiddling 2 | // 3 | // Tool to fiddle with json strings 4 | 5 | package main 6 | 7 | //////////////////////////////////////////////////////////////////////////// 8 | // Program: jsonfiddle 9 | // Purpose: JSON Fiddling 10 | // Authors: Tong Sun (c) 2017-2025, All rights reserved 11 | //////////////////////////////////////////////////////////////////////////// 12 | 13 | import ( 14 | // "fmt" 15 | // "os" 16 | 17 | // "github.com/go-easygen/go-flags" 18 | ) 19 | 20 | // Template for main starts here 21 | 22 | // // for `go generate -x` 23 | // //go:generate sh jsonfiddle_cliGen.sh 24 | 25 | ////////////////////////////////////////////////////////////////////////// 26 | // Constant and data type/structure definitions 27 | 28 | //////////////////////////////////////////////////////////////////////////// 29 | // Global variables definitions 30 | 31 | // var ( 32 | // progname = "jsonfiddle" 33 | // version = "0.1.0" 34 | // date = "2025-11-18" 35 | 36 | // // Opts store all the configurable options 37 | // Opts OptsT 38 | // ) 39 | // 40 | // var gfParser = flags.NewParser(&Opts, flags.Default) 41 | 42 | //////////////////////////////////////////////////////////////////////////// 43 | // Function definitions 44 | 45 | //========================================================================== 46 | // Function main 47 | // func main() { 48 | // Opts.Version = showVersion 49 | // Opts.Verbflg = func() { 50 | // Opts.Verbose++ 51 | // } 52 | // 53 | // if _, err := gfParser.Parse(); err != nil { 54 | // fmt.Println() 55 | // gfParser.WriteHelp(os.Stdout) 56 | // os.Exit(1) 57 | // } 58 | // fmt.Println() 59 | // //DoJsonfiddle() 60 | // } 61 | // 62 | // //========================================================================== 63 | // // support functions 64 | // 65 | // func showVersion() { 66 | // fmt.Fprintf(os.Stderr, "jsonfiddle - JSON Fiddling, version %s\n", version) 67 | // fmt.Fprintf(os.Stderr, "Built on %s\n", date) 68 | // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2025, Tong Sun\n\n") 69 | // fmt.Fprintf(os.Stderr, "Tool to fiddle with json strings\n") 70 | // os.Exit(0) 71 | // } 72 | // Template for main ends here 73 | 74 | // DoJsonfiddle implements the business logic of command `jsonfiddle` 75 | // func DoJsonfiddle() error { 76 | // return nil 77 | // } 78 | 79 | // Template for type define starts here 80 | 81 | // The OptsT type defines all the configurable options from cli. 82 | type OptsT struct { 83 | Compact bool `short:"c" long:"compact" description:"Compact JSON data, remove all whitespaces"` 84 | Prefix string `long:"prefix" description:"prefix for json string output"` 85 | Indent string `short:"d" long:"indent" description:"indent for json string output" default:" "` 86 | Protect bool `short:"p" long:"protect" description:"protect {{TEMPLATE}} in JSON data"` 87 | Verbflg func() `short:"v" long:"verbose" description:"Verbose mode (Multiple -v options increase the verbosity)"` 88 | Verbose int 89 | Version func() `short:"V" long:"version" description:"Show program version and exit"` 90 | } 91 | 92 | // Template for type define ends here 93 | 94 | // Template for "esc" CLI handling starts here 95 | //////////////////////////////////////////////////////////////////////////// 96 | // Program: jsonfiddle 97 | // Purpose: JSON Fiddling 98 | // Authors: Tong Sun (c) 2017-2025, All rights reserved 99 | //////////////////////////////////////////////////////////////////////////// 100 | 101 | // package main 102 | 103 | // import ( 104 | // "fmt" 105 | // "os" 106 | // 107 | // "github.com/go-easygen/go-flags/clis" 108 | // ) 109 | 110 | // *** Sub-command: esc *** 111 | 112 | //////////////////////////////////////////////////////////////////////////// 113 | // Constant and data type/structure definitions 114 | 115 | // The EscCommand type defines all the configurable options from cli. 116 | // type EscCommand struct { 117 | // Filei string `short:"i" long:"input" description:"the source to get json string from (or \"-\" for stdin) (mandatory)" required:"true"` 118 | // Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 119 | // } 120 | 121 | // 122 | // var escCommand EscCommand 123 | // 124 | // //////////////////////////////////////////////////////////////////////////// 125 | // // Function definitions 126 | // 127 | // func init() { 128 | // gfParser.AddCommand("esc", 129 | // "Escape json string", 130 | // ` 131 | // `, 132 | // &escCommand) 133 | // } 134 | // 135 | // func (x *EscCommand) Execute(args []string) error { 136 | // fmt.Fprintf(os.Stderr, "Escape json string\n") 137 | // // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2025, Tong Sun\n\n") 138 | // clis.Setup("jsonfiddle::esc", Opts.Verbose) 139 | // clis.Verbose(1, "Doing Esc, with %+v, %+v", Opts, args) 140 | // // fmt.Println(x.Filei, x.Fileo) 141 | // return x.Exec(args) 142 | // } 143 | // 144 | // // Exec implements the business logic of command `esc` 145 | // func (x *EscCommand) Exec(args []string) error { 146 | // // err := ... 147 | // // clis.WarnOn("esc::Exec", err) 148 | // // or, 149 | // // clis.AbortOn("esc::Exec", err) 150 | // return nil 151 | // } 152 | // Template for "esc" CLI handling ends here 153 | 154 | // Template for "fmt" CLI handling starts here 155 | //////////////////////////////////////////////////////////////////////////// 156 | // Program: jsonfiddle 157 | // Purpose: JSON Fiddling 158 | // Authors: Tong Sun (c) 2017-2025, All rights reserved 159 | //////////////////////////////////////////////////////////////////////////// 160 | 161 | // package main 162 | 163 | // import ( 164 | // "fmt" 165 | // "os" 166 | // 167 | // "github.com/go-easygen/go-flags/clis" 168 | // ) 169 | 170 | // *** Sub-command: fmt *** 171 | 172 | //////////////////////////////////////////////////////////////////////////// 173 | // Constant and data type/structure definitions 174 | 175 | // The FmtCommand type defines all the configurable options from cli. 176 | // type FmtCommand struct { 177 | // Filei string `short:"i" long:"input" description:"the source to get json string from (mandatory)" required:"true"` 178 | // Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 179 | // Concise bool `short:"s" long:"concise" description:"Compact the top level array into concise array style"` 180 | // Unescape bool `short:"u" long:"unescape" description:"Unescape unicode of form \u003c to their literal characters"` 181 | // } 182 | 183 | // 184 | // var fmtCommand FmtCommand 185 | // 186 | // //////////////////////////////////////////////////////////////////////////// 187 | // // Function definitions 188 | // 189 | // func init() { 190 | // gfParser.AddCommand("fmt", 191 | // "Format json string", 192 | // ` 193 | // `, 194 | // &fmtCommand) 195 | // } 196 | // 197 | // func (x *FmtCommand) Execute(args []string) error { 198 | // fmt.Fprintf(os.Stderr, "Format json string\n") 199 | // // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2025, Tong Sun\n\n") 200 | // clis.Setup("jsonfiddle::fmt", Opts.Verbose) 201 | // clis.Verbose(1, "Doing Fmt, with %+v, %+v", Opts, args) 202 | // // fmt.Println(x.Filei, x.Fileo, x.Concise, x.Unescape) 203 | // return x.Exec(args) 204 | // } 205 | // 206 | // // Exec implements the business logic of command `fmt` 207 | // func (x *FmtCommand) Exec(args []string) error { 208 | // // err := ... 209 | // // clis.WarnOn("fmt::Exec", err) 210 | // // or, 211 | // // clis.AbortOn("fmt::Exec", err) 212 | // return nil 213 | // } 214 | // Template for "fmt" CLI handling ends here 215 | 216 | // Template for "sort" CLI handling starts here 217 | //////////////////////////////////////////////////////////////////////////// 218 | // Program: jsonfiddle 219 | // Purpose: JSON Fiddling 220 | // Authors: Tong Sun (c) 2017-2025, All rights reserved 221 | //////////////////////////////////////////////////////////////////////////// 222 | 223 | // package main 224 | 225 | // import ( 226 | // "fmt" 227 | // "os" 228 | // 229 | // "github.com/go-easygen/go-flags/clis" 230 | // ) 231 | 232 | // *** Sub-command: sort *** 233 | 234 | //////////////////////////////////////////////////////////////////////////// 235 | // Constant and data type/structure definitions 236 | 237 | // The SortCommand type defines all the configurable options from cli. 238 | // type SortCommand struct { 239 | // Filei string `short:"i" long:"input" description:"the source to get json string from (mandatory)" required:"true"` 240 | // Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 241 | // } 242 | 243 | // 244 | // var sortCommand SortCommand 245 | // 246 | // //////////////////////////////////////////////////////////////////////////// 247 | // // Function definitions 248 | // 249 | // func init() { 250 | // gfParser.AddCommand("sort", 251 | // "Sort json fields recursively", 252 | // ` 253 | // `, 254 | // &sortCommand) 255 | // } 256 | // 257 | // func (x *SortCommand) Execute(args []string) error { 258 | // fmt.Fprintf(os.Stderr, "Sort json fields recursively\n") 259 | // // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2025, Tong Sun\n\n") 260 | // clis.Setup("jsonfiddle::sort", Opts.Verbose) 261 | // clis.Verbose(1, "Doing Sort, with %+v, %+v", Opts, args) 262 | // // fmt.Println(x.Filei, x.Fileo) 263 | // return x.Exec(args) 264 | // } 265 | // 266 | // // Exec implements the business logic of command `sort` 267 | // func (x *SortCommand) Exec(args []string) error { 268 | // // err := ... 269 | // // clis.WarnOn("sort::Exec", err) 270 | // // or, 271 | // // clis.AbortOn("sort::Exec", err) 272 | // return nil 273 | // } 274 | // Template for "sort" CLI handling ends here 275 | 276 | // Template for "j2s" CLI handling starts here 277 | //////////////////////////////////////////////////////////////////////////// 278 | // Program: jsonfiddle 279 | // Purpose: JSON Fiddling 280 | // Authors: Tong Sun (c) 2017-2025, All rights reserved 281 | //////////////////////////////////////////////////////////////////////////// 282 | 283 | // package main 284 | 285 | // import ( 286 | // "fmt" 287 | // "os" 288 | // 289 | // "github.com/go-easygen/go-flags/clis" 290 | // ) 291 | 292 | // *** Sub-command: j2s *** 293 | 294 | //////////////////////////////////////////////////////////////////////////// 295 | // Constant and data type/structure definitions 296 | 297 | // The J2sCommand type defines all the configurable options from cli. 298 | // type J2sCommand struct { 299 | // FmtType string `short:"f" long:"fmt" description:"the structural format of the input data (json/yaml)" default:"json"` 300 | // Filei string `short:"i" long:"input" description:"the source of the input JSON (mandatory)" required:"true"` 301 | // Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 302 | // Name string `long:"name" description:"the name of the root struct (default: as input file name)"` 303 | // Pkg string `long:"pkg" description:"the name of the package for the generated code" default:"main"` 304 | // SubStruct bool `long:"subStruct" description:"create types for sub-structs"` 305 | // } 306 | 307 | // 308 | // var j2sCommand J2sCommand 309 | // 310 | // //////////////////////////////////////////////////////////////////////////// 311 | // // Function definitions 312 | // 313 | // func init() { 314 | // gfParser.AddCommand("j2s", 315 | // "JSON to struct", 316 | // `JSON convert to Go struct 317 | // `, 318 | // &j2sCommand) 319 | // } 320 | // 321 | // func (x *J2sCommand) Execute(args []string) error { 322 | // fmt.Fprintf(os.Stderr, "JSON to struct\n") 323 | // // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2025, Tong Sun\n\n") 324 | // clis.Setup("jsonfiddle::j2s", Opts.Verbose) 325 | // clis.Verbose(1, "Doing J2s, with %+v, %+v", Opts, args) 326 | // // fmt.Println(x.FmtType, x.Filei, x.Fileo, x.Name, x.Pkg, x.SubStruct) 327 | // return x.Exec(args) 328 | // } 329 | // 330 | // // Exec implements the business logic of command `j2s` 331 | // func (x *J2sCommand) Exec(args []string) error { 332 | // // err := ... 333 | // // clis.WarnOn("j2s::Exec", err) 334 | // // or, 335 | // // clis.AbortOn("j2s::Exec", err) 336 | // return nil 337 | // } 338 | // Template for "j2s" CLI handling ends here 339 | 340 | // Template for "x2j" CLI handling starts here 341 | //////////////////////////////////////////////////////////////////////////// 342 | // Program: jsonfiddle 343 | // Purpose: JSON Fiddling 344 | // Authors: Tong Sun (c) 2017-2025, All rights reserved 345 | //////////////////////////////////////////////////////////////////////////// 346 | 347 | // package main 348 | 349 | // import ( 350 | // "fmt" 351 | // "os" 352 | // 353 | // "github.com/go-easygen/go-flags/clis" 354 | // ) 355 | 356 | // *** Sub-command: x2j *** 357 | 358 | //////////////////////////////////////////////////////////////////////////// 359 | // Constant and data type/structure definitions 360 | 361 | // The X2jCommand type defines all the configurable options from cli. 362 | // type X2jCommand struct { 363 | // Filei string `short:"i" long:"input" description:"the source of the input JSON (mandatory)" required:"true"` 364 | // Fileo string `short:"o" long:"output" description:"the output, default to stdout" default:"-"` 365 | // } 366 | 367 | // 368 | // var x2jCommand X2jCommand 369 | // 370 | // //////////////////////////////////////////////////////////////////////////// 371 | // // Function definitions 372 | // 373 | // func init() { 374 | // gfParser.AddCommand("x2j", 375 | // "XML to JSON", 376 | // ` 377 | // `, 378 | // &x2jCommand) 379 | // } 380 | // 381 | // func (x *X2jCommand) Execute(args []string) error { 382 | // fmt.Fprintf(os.Stderr, "XML to JSON\n") 383 | // // fmt.Fprintf(os.Stderr, "Copyright (C) 2017-2025, Tong Sun\n\n") 384 | // clis.Setup("jsonfiddle::x2j", Opts.Verbose) 385 | // clis.Verbose(1, "Doing X2j, with %+v, %+v", Opts, args) 386 | // // fmt.Println(x.Filei, x.Fileo) 387 | // return x.Exec(args) 388 | // } 389 | // 390 | // // Exec implements the business logic of command `x2j` 391 | // func (x *X2jCommand) Exec(args []string) error { 392 | // // err := ... 393 | // // clis.WarnOn("x2j::Exec", err) 394 | // // or, 395 | // // clis.AbortOn("x2j::Exec", err) 396 | // return nil 397 | // } 398 | // Template for "x2j" CLI handling ends here 399 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # jsonfiddle 3 | 4 | [![MIT License](http://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) 5 | [![GoDoc](https://godoc.org/github.com/go-jsonfile/jsonfiddle?status.svg)](http://godoc.org/github.com/go-jsonfile/jsonfiddle) 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/go-jsonfile/jsonfiddle)](https://goreportcard.com/report/github.com/go-jsonfile/jsonfiddle) 7 | [![travis Status](https://travis-ci.org/go-jsonfile/jsonfiddle.svg?branch=master)](https://travis-ci.org/go-jsonfile/jsonfiddle) 8 | [![PoweredBy WireFrame](https://github.com/go-easygen/wireframe/blob/master/PoweredBy-WireFrame-R.svg)](http://godoc.org/github.com/go-easygen/wireframe) 9 | 10 | ## TOC 11 | - [jsonfiddle - JSON Fiddling](#jsonfiddle---json-fiddling) 12 | - [Usage](#usage) 13 | - [$ jsonfiddle || true](#-jsonfiddle--true) 14 | - [$ jsonfiddle esc || true](#-jsonfiddle-esc--true) 15 | - [$ jsonfiddle sort || true](#-jsonfiddle-sort--true) 16 | - [$ jsonfiddle x2j || true](#-jsonfiddle-x2j--true) 17 | 18 | ## jsonfiddle - JSON Fiddling 19 | 20 | The `jsonfiddle` makes it easy to look at the JSON data from different aspects. 21 | 22 | - **`jsonfiddle esc`** will escape any arbitrary string so as to embed it as content of json string. 23 | - **`jsonfiddle fmt`** will format the JSON data, either compact it or pretty printing it. The order of fields are intact. 24 | - **`jsonfiddle sort`** will sort the JSON data fields recursively, so that the attributes at any level are in sorted order. 25 | - **`jsonfiddle x2j`** means xml to json. It will convert data from xml format into json. 26 | - **`jsonfiddle j2s`** means json to struct. It will extract the structure of JSON data as Go struct. 27 | 28 | # Usage 29 | 30 | ``` 31 | $ jsonfiddle -V 32 | jsonfiddle - JSON Fiddling, version 0.6.0 33 | Built on 2025-11-18 34 | Copyright (C) 2017-2025, Tong Sun 35 | 36 | Tool to fiddle with json strings 37 | ``` 38 | 39 | ### $ jsonfiddle || true 40 | ```sh 41 | Please specify one command of: esc, fmt, j2s, sort or x2j 42 | 43 | Usage: 44 | jsonfiddle [OPTIONS] 45 | 46 | Application Options: 47 | -c, --compact Compact JSON data, remove all whitespaces 48 | --prefix= prefix for json string output 49 | -d, --indent= indent for json string output (default: ) 50 | -p, --protect protect {{TEMPLATE}} in JSON data 51 | -v, --verbose Verbose mode (Multiple -v options increase the verbosity) 52 | -V, --version Show program version and exit 53 | 54 | Help Options: 55 | -h, --help Show this help message 56 | 57 | Available commands: 58 | esc Escape json string 59 | fmt Format json string 60 | j2s JSON to struct 61 | sort Sort json fields recursively 62 | x2j XML to JSON 63 | ``` 64 | 65 | ### $ jsonfiddle esc || true 66 | ```sh 67 | the required flag `-i, --input' was not specified 68 | 69 | Usage: 70 | jsonfiddle [OPTIONS] esc [esc-OPTIONS] 71 | 72 | Application Options: 73 | -c, --compact Compact JSON data, remove all whitespaces 74 | --prefix= prefix for json string output 75 | -d, --indent= indent for json string output (default: ) 76 | -p, --protect protect {{TEMPLATE}} in JSON data 77 | -v, --verbose Verbose mode (Multiple -v options increase the verbosity) 78 | -V, --version Show program version and exit 79 | 80 | Help Options: 81 | -h, --help Show this help message 82 | 83 | [esc command options] 84 | -i, --input= the source to get json string from (or "-" for stdin) 85 | (mandatory) 86 | -o, --output= the output, default to stdout (default: -) 87 | ``` 88 | 89 | ### $ jsonfiddle fmt || true 90 | ```sh 91 | the required flag `-i, --input' was not specified 92 | 93 | Usage: 94 | jsonfiddle [OPTIONS] fmt [fmt-OPTIONS] 95 | 96 | 97 | 98 | Application Options: 99 | -c, --compact Compact JSON data, remove all whitespaces 100 | --prefix= prefix for json string output 101 | -d, --indent= indent for json string output (default: ) 102 | -p, --protect protect {{TEMPLATE}} in JSON data 103 | -v, --verbose Verbose mode (Multiple -v options increase the verbosity) 104 | -V, --version Show program version and exit 105 | 106 | Help Options: 107 | -h, --help Show this help message 108 | 109 | [fmt command options] 110 | -i, --input= the source to get json string from (mandatory) 111 | -o, --output= the output, default to stdout (default: -) 112 | -s, --concise Compact the top level array into concise array style 113 | -u, --unescape Unescape unicode of form < to their literal characters 114 | ``` 115 | 116 | ### $ jsonfiddle sort || true 117 | ```sh 118 | the required flag `-i, --input' was not specified 119 | 120 | Usage: 121 | jsonfiddle [OPTIONS] sort [sort-OPTIONS] 122 | 123 | Application Options: 124 | -c, --compact Compact JSON data, remove all whitespaces 125 | --prefix= prefix for json string output 126 | -d, --indent= indent for json string output (default: ) 127 | -p, --protect protect {{TEMPLATE}} in JSON data 128 | -v, --verbose Verbose mode (Multiple -v options increase the verbosity) 129 | -V, --version Show program version and exit 130 | 131 | Help Options: 132 | -h, --help Show this help message 133 | 134 | [sort command options] 135 | -i, --input= the source to get json string from (mandatory) 136 | -o, --output= the output, default to stdout (default: -) 137 | ``` 138 | 139 | ### $ jsonfiddle j2s || true 140 | ```sh 141 | the required flag `-i, --input' was not specified 142 | 143 | Usage: 144 | jsonfiddle [OPTIONS] j2s [j2s-OPTIONS] 145 | 146 | JSON convert to Go struct 147 | 148 | Application Options: 149 | -c, --compact Compact JSON data, remove all whitespaces 150 | --prefix= prefix for json string output 151 | -d, --indent= indent for json string output (default: ) 152 | -p, --protect protect {{TEMPLATE}} in JSON data 153 | -v, --verbose Verbose mode (Multiple -v options increase the verbosity) 154 | -V, --version Show program version and exit 155 | 156 | Help Options: 157 | -h, --help Show this help message 158 | 159 | [j2s command options] 160 | -f, --fmt= the structural format of the input data (json/yaml) 161 | (default: json) 162 | -i, --input= the source of the input JSON (mandatory) 163 | -o, --output= the output, default to stdout (default: -) 164 | --name= the name of the root struct (default: as input file name) 165 | --pkg= the name of the package for the generated code (default: 166 | main) 167 | --subStruct create types for sub-structs 168 | ``` 169 | 170 | ### $ jsonfiddle x2j || true 171 | ```sh 172 | the required flag `-i, --input' was not specified 173 | 174 | Usage: 175 | jsonfiddle [OPTIONS] x2j [x2j-OPTIONS] 176 | 177 | Application Options: 178 | -c, --compact Compact JSON data, remove all whitespaces 179 | --prefix= prefix for json string output 180 | -d, --indent= indent for json string output (default: ) 181 | -p, --protect protect {{TEMPLATE}} in JSON data 182 | -v, --verbose Verbose mode (Multiple -v options increase the verbosity) 183 | -V, --version Show program version and exit 184 | 185 | Help Options: 186 | -h, --help Show this help message 187 | 188 | [x2j command options] 189 | -i, --input= the source of the input JSON (mandatory) 190 | -o, --output= the output, default to stdout (default: -) 191 | ``` 192 | 193 | # Examples 194 | 195 | ## Escape with `jsonfiddle esc` 196 | 197 | ### $ jsonfiddle esc -i test/Customer.ref 2>/dev/null 198 | ```json 199 | "{\n \"firstName\": \"John\",\n \"lastName\": \"Smith\",\n \"age\": 25,\n \"address\": {\n \"streetAddress\": \"21 2nd Street\",\n \"city\": \"New York\",\n \"state\": \"NY\",\n \"postalCode\": \"10021\"\n },\n \"phoneNumber\": [\n {\n \"type\": \"home\",\n \"number\": \"212 555-1234\"\n },\n {\n \"type\": \"fax\",\n \"number\": \"646 555-4567\"\n }\n ]\n}\n\n" 200 | ``` 201 | 202 | ### Usage 203 | 204 | `jsonfiddle esc` will escape any arbitrary string so as to embed it as content of json string. This seems useless at first, but it actually allows you to embed any arbitrary file into [GitHub Gists JSON API](https://developer.github.com/v3/gists/), so as to post any arbitrary file onto GitHub Gist: 205 | 206 | 207 | echo '{"description":"SmartyStreets API Demo","public":true,"files":{"SmartyStreets.json":{"content":'"`jsonfiddle fmt -i test/SmartyStreets.json | jsonfiddle esc -i`"'}}}' | curl --data @- https://api.github.com/gists 208 | 209 | This will give you 210 | https://gist.github.com/anonymous/1423d4768dd9b88262ca513626e68d8e 211 | 212 | 213 | By "_arbitrary file_" I do mean arbitrary file. Check this out: 214 | https://gist.github.com/anonymous/a51798ce99ff59d8d4ba536cbf4b6996 215 | 216 | This is why `jsonfiddle esc` is a command on its own, instead of being part of functionalities of `jsonfiddle fmt` or `jsonfiddle sort`. 217 | 218 | ## Format with `jsonfiddle fmt` 219 | 220 | ### Pretty print 221 | 222 | $ jsonfiddle fmt -i test/Customer.json 223 | 224 | #### > test/CustomerSI.ref 225 | ```json 226 | { 227 | "address": { 228 | "city": "New York", 229 | "postalCode": "10021", 230 | "state": "NY", 231 | "streetAddress": "21 2nd Street" 232 | }, 233 | "age": 25, 234 | "firstName": "John", 235 | "lastName": "Smith", 236 | "phoneNumber": [ 237 | { 238 | "number": "212 555-1234", 239 | "type": "home" 240 | }, 241 | { 242 | "number": "646 555-4567", 243 | "type": "fax" 244 | } 245 | ] 246 | } 247 | ``` 248 | 249 | ### Protect templates in json data 250 | 251 | There are times that json data may contain templates, i.e., strings like `{{VARIABLE}}`. Some of the pretty printing tools, like the json plugin in Notepad++, cannot handle such template forms well, and will turn `{{VARIABLE}}` into: 252 | 253 | ```json 254 | { 255 | { 256 | VARIABLE 257 | } 258 | } 259 | ``` 260 | 261 | What's worse is that when such template variables are for `int`, e.g.: `"age":{{Var_Age}}`, they then wouldn't be able to handle it, for inputs like 262 | test/CustomerP.json 263 | ```sh 264 | {"firstName":"{{C_firstName}}","lastName":"{{C_lastName}}","age":{{C_age}},"address":{"streetAddress":"{{C_address1}}","city":"{{C_city}}","state":"NY","postalCode":"10021"}} 265 | ``` 266 | 267 | To make such template variables work for those tools, the `-p,--protect` option is introduced: 268 | 269 | $ jsonfiddle fmt -p -i test/CustomerP.json 270 | 271 | #### > test/CustomerP.ref 272 | ```json 273 | { 274 | "firstName": "<>", 275 | "lastName": "<>", 276 | "age": "<>", 277 | "address": { 278 | "streetAddress": "<>", 279 | "city": "<>", 280 | "state": "NY", 281 | "postalCode": "10021" 282 | } 283 | } 284 | ``` 285 | 286 | ### Compact 287 | 288 | $ jsonfiddle fmt -c -i test/Customer.json 289 | 290 | #### > test/CustomerC.ref 291 | ```json 292 | {"firstName":"John","lastName":"Smith","age":25,"address":{"streetAddress":"21 2nd Street","city":"New York","state":"NY","postalCode":"10021"},"phoneNumber":[{"type":"home","number":"212 555-1234"},{"type":"fax","number":"646 555-4567"}]} 293 | ``` 294 | 295 | You can also do, 296 | 297 | $ cat Customer.json | jsonfiddle fmt -c -i - 298 | 299 | and the result is the same (and for all other examples using `-i` as well). 300 | 301 | ## Sort fields with `jsonfiddle sort` 302 | 303 | ### Sort in compact 304 | 305 | $ jsonfiddle sort -c -i test/Customer.json 306 | 307 | #### > test/CustomerSC.ref 308 | ```json 309 | {"address":{"city":"New York","postalCode":"10021","state":"NY","streetAddress":"21 2nd Street"},"age":25,"firstName":"John","lastName":"Smith","phoneNumber":[{"number":"212 555-1234","type":"home"},{"number":"646 555-4567","type":"fax"}]} 310 | ``` 311 | 312 | ### Sort with pretty print 313 | 314 | $ jsonfiddle sort -i test/Customer.json 315 | 316 | #### > test/CustomerSI.ref 317 | ```json 318 | { 319 | "address": { 320 | "city": "New York", 321 | "postalCode": "10021", 322 | "state": "NY", 323 | "streetAddress": "21 2nd Street" 324 | }, 325 | "age": 25, 326 | "firstName": "John", 327 | "lastName": "Smith", 328 | "phoneNumber": [ 329 | { 330 | "number": "212 555-1234", 331 | "type": "home" 332 | }, 333 | { 334 | "number": "646 555-4567", 335 | "type": "fax" 336 | } 337 | ] 338 | } 339 | ``` 340 | 341 | ### XML to JSON, sort then pretty print 342 | 343 | ``` 344 | $ jsonfiddle x2j -i test/Books.xml | jsonfiddle sort -i - | jsonfiddle fmt -i - 345 | Format json string 346 | XML to JSON 347 | jsonfiddle v0.6.0. x2j - XML to JSON 348 | Sort json fields recursively 349 | { 350 | "catalog": { 351 | "book": [ 352 | { 353 | "-id": "bk101", 354 | "author": "Gambardella, Matthew", 355 | "description": "An in-depth look at creating applications \n with XML.", 356 | "genre": "Computer", 357 | "price": "44.95", 358 | "publish_date": "2000-10-01", 359 | "title": "XML Developer's Guide" 360 | }, 361 | { 362 | "-id": "bk102", 363 | "author": "Ralls, Kim", 364 | "description": "A former architect battles corporate zombies, \n an evil sorceress, and her own childhood to become queen \n of the world.", 365 | "genre": "Fantasy", 366 | "price": "5.95", 367 | "publish_date": "2000-12-16", 368 | "title": "Midnight Rain" 369 | }, 370 | { 371 | "-id": "bk103", 372 | "author": "Corets, Eva", 373 | "description": "After the collapse of a nanotechnology \n society in England, the young survivors lay the \n foundation for a new society.", 374 | "genre": "Fantasy", 375 | "price": "5.95", 376 | "publish_date": "2000-11-17", 377 | "title": "Maeve Ascendant" 378 | } 379 | ] 380 | } 381 | } 382 | ``` 383 | 384 | ## JSON to struct via `jsonfiddle j2s` 385 | 386 | $ jsonfiddle j2s -i test/Customer.json 387 | 388 | #### > test/CustomerJ2S.ref 389 | ```go 390 | package main 391 | 392 | type Customer struct { 393 | Address struct { 394 | City string `json:"city"` 395 | PostalCode string `json:"postalCode"` 396 | State string `json:"state"` 397 | StreetAddress string `json:"streetAddress"` 398 | } `json:"address"` 399 | Age int64 `json:"age"` 400 | FirstName string `json:"firstName"` 401 | LastName string `json:"lastName"` 402 | PhoneNumber []struct { 403 | Number string `json:"number"` 404 | Type string `json:"type"` 405 | } `json:"phoneNumber"` 406 | } 407 | ``` 408 | 409 | 410 | # Purpose 411 | 412 | A few more words on why I'm writing the tool -- because I need to compare JSON string that are roughly close and very complicated in the mean time -- sometimes even less than 30% of fields are the same, of course, this is after their having been sorted, otherwise, it'd be 100% different. 413 | 414 | Thus all the JSON comparison tools I found are failing under such hash request. So far, I personally find that 415 | 416 | - Sorting the JSON data fields recursively and producing plain text file (via `jsonfiddle sort`), then use the state-of-the-art text comparison tools to compare them is the best approach, for my above scenario. 417 | - For extremely long and very complicated JSONs, converting json to abstract Go struct (via `jsonfiddle j2s`) is the quickest approach to compare them at higher level. 418 | 419 | # Download binaries 420 | 421 | - The latest binary executables are available under 422 | https://github.com/go-jsonfile/jsonfiddle/releases 423 | as the result of the Continuous-Integration process. 424 | - I.e., they are built right from the source code during every git tagging commit automatically. 425 | - Pick & choose the binary executable that suits your OS and its architecture. E.g., for Linux, it would most probably be the `jsonfiddle_linux_VER_amd64` file. If your OS and its architecture is not available in the download list, please let me know and I'll add it. 426 | - You may want to rename it to a shorter name instead, e.g., `jsonfiddle`, after downloading it. 427 | 428 | 429 | # Debian package 430 | 431 | Available at the above releases url as well. 432 | 433 | # Install Source 434 | 435 | To install the source code instead: 436 | 437 | ``` 438 | go get github.com/go-jsonfile/jsonfiddle 439 | ``` 440 | 441 | 442 | ## Credits 443 | 444 | - [Ladicle/gojson](https://github.com/Ladicle/gojson) forked source for JSON to struct 445 | - [ChimeraCoder/gojson](https://github.com/ChimeraCoder/gojson) the original source of [Ladicle/gojson](https://github.com/Ladicle/gojson). 446 | 447 | ## Similar Projects 448 | 449 | All the following similar projects have been considered before writing one on my own instead. 450 | 451 | . . . to be filled . . . 452 | 453 | ## Author(s) & Contributor(s) 454 | 455 | Tong SUN 456 | ![suntong from cpan.org](https://img.shields.io/badge/suntong-%40cpan.org-lightgrey.svg "suntong from cpan.org") 457 | 458 | _Powered by_ [**WireFrame**](https://github.com/go-easygen/wireframe), [![PoweredBy WireFrame](https://github.com/go-easygen/wireframe/blob/master/PoweredBy-WireFrame-Y.svg)](http://godoc.org/github.com/go-easygen/wireframe), the _one-stop wire-framing solution_ for Go cli based projects, from start to deploy. 459 | 460 | All patches welcome. 461 | -------------------------------------------------------------------------------- /test/friendfeed_oww.json: -------------------------------------------------------------------------------- 1 | [{ "_id" : "e/311a8abb31474a30a6e41e405ad163f7", "body" : "OWW Lab Notebook - http://openwetware.org/wiki...", "from" : { "type" : "user", "id" : "rvidal", "name" : "Ricardo Vidal" }, "url" : "http://friendfeed.com/oww/311a8abb/oww-lab-notebook", "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "date" : "2008-07-27T23:45:14Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/5d2b5d3a8d3d425894e905206860f879", "body" : "Starting a page fro group edit on OWW. Are there any "how-to" pages for users that outline how to best use OWW for collaborative docs?", "from" : { "type" : "user", "id" : "ebola", "name" : "Maureen" }, "url" : "http://friendfeed.com/oww/5d2b5d3a/starting-page-fro-group-edit-on-oww-are-there-any", "comments" : [ { "date" : "2008-08-04T19:10:15Z", "body" : "Not that I know of - although such a thing would be useful. The key thing is to keep people engaged and contributing. Also to understand that different people have different comfort levels when it comes to editing other people's stuff.", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" }, "id" : "e/5d2b5d3a8d3d425894e905206860f879/c/79faf71b14314615bd845e81f488e7d8" }, { "date" : "2008-08-04T20:52:24Z", "body" : "Not quite sure we have a "How-to" for something like this. That's an interesting idea. Should we collaborate on a "how-to" collaborate page? :-)", "from" : { "type" : "user", "id" : "rvidal", "name" : "Ricardo Vidal" }, "id" : "e/5d2b5d3a8d3d425894e905206860f879/c/18e299578ec441168d14df88eb806819" }, { "date" : "2008-08-04T21:04:43Z", "body" : "Thanks Cameron and and Ricardo. I think a how-to page for document collaboration would be useful to organize work. For example, suggesting that edits go on the doc and comments or global changes go on the talk page. We could use the draft for the OWW NSF grant as an example perhaps. see talk page at http://openwetware.org/wiki...", "from" : { "type" : "user", "id" : "ebola", "name" : "Maureen" }, "id" : "e/5d2b5d3a8d3d425894e905206860f879/c/0cfe1eba4eed44aabca65b5eb9dc95aa" } ], "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "date" : "2008-08-04T18:21:03Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/d2a16061f75b47d3a79b5d9c099397cb", "body" : "MyNetResearch | Online collaborative research community & tools - http://www.mynetresearch.com/Default...", "from" : { "type" : "user", "id" : "ebola", "name" : "Maureen" }, "url" : "http://friendfeed.com/oww/d2a16061/mynetresearch-online-collaborative-research", "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2008-11-12T08:22:22Z", "from" : { "type" : "user", "id" : "shameer", "name" : "Khader Shameer" } } ], "date" : "2008-08-26T14:50:25Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/d9b35157b7304b81a43e320922e19187", "body" : "Best Online Collaboration Tools 2008 - The Collaborative Map - http://www.masternewmedia.org/best-on...", "from" : { "type" : "user", "id" : "mikechelen", "name" : "Mike Chelen" }, "url" : "http://friendfeed.com/oww/d9b35157/best-online-collaboration-tools-2008", "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2008-11-27T04:23:33Z", "from" : { "type" : "user", "id" : "nuin", "name" : "pn" } } ], "date" : "2008-11-27T04:17:13Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/12b3340501ed4322802f2f79bd17dc5e", "body" : "Recent OWW site developments - http://groups.google.com/group...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/oww/12b33405/recent-oww-site-developments", "comments" : [ { "date" : "2009-01-13T16:06:57Z", "body" : "Not sure if anyone uses this room, but thought I would share here.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/12b3340501ed4322802f2f79bd17dc5e/c/2d1b461aa6ef4b878ded29ff3246f4de" }, { "date" : "2009-01-13T17:10:13Z", "body" : "I'm subscribed but there is not a lot of activity", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" }, "id" : "e/12b3340501ed4322802f2f79bd17dc5e/c/fedc882bd4d7444fa4e015ae49c23388" } ], "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2009-01-13T17:22:09Z", "from" : { "type" : "user", "id" : "yokofakun", "name" : "Pierre Lindenbaum" } }, { "date" : "2009-01-13T17:09:55Z", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" } }, { "date" : "2009-01-13T16:25:08Z", "from" : { "type" : "user", "id" : "rvidal", "name" : "Ricardo Vidal" } } ], "date" : "2009-01-13T16:06:57Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/313bfb22fdd6450ba0588f1cef82a29b", "body" : "Message from Bill about adding javascript gadgets to OWW. I don't understand it technically, but it sounds great to me. - http://groups.google.com/group...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/oww/313bfb22/message-from-bill-about-adding-javascript", "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "date" : "2009-01-15T17:57:51Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/1132852594744a2298d02958dda97051", "body" : "Javascript Gadgets Coming to OWW - http://blog.openwetware.org/communi...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/oww/11328525/javascript-gadgets-coming-to-oww", "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "date" : "2009-01-18T14:20:03Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/6a3c9db238184c2487693a51cc07f1b7", "body" : "Koch Lab Research blog about Andy's instructions for laser diode system. - http://kochlab.blogspot.com/2009...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/oww/6a3c9db2/koch-lab-research-blog-about-andy-instructions", "comments" : [ { "date" : "2009-01-25T06:27:55Z", "body" : "I talk about a really cool page on how to assemble a laser diode system. Written by Andy Maloney, grad student in our lab, with help from other students.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/6a3c9db238184c2487693a51cc07f1b7/c/6f2a9b1f8cf74e1db2b548cba5378679" }, { "date" : "2009-01-25T06:40:10Z", "body" : "Oh very cool. Brings back memories of my grad school days", "from" : { "type" : "user", "id" : "mndoci", "name" : "Deepak Singh" }, "id" : "e/6a3c9db238184c2487693a51cc07f1b7/c/4aae27f87cd64114b20536bb45646431" }, { "date" : "2009-01-25T06:51:28Z", "body" : "Thanks! And I hope it's bringing back the good memories :)", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/6a3c9db238184c2487693a51cc07f1b7/c/0eafefa517b44a72966d32bc1c8d6135" }, { "date" : "2009-01-25T06:57:32Z", "body" : "Most of them anyway :)", "from" : { "type" : "user", "id" : "mndoci", "name" : "Deepak Singh" }, "id" : "e/6a3c9db238184c2487693a51cc07f1b7/c/8b977295715c40f7b7af66add0481fe3" } ], "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2009-01-25T13:26:22Z", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" } }, { "date" : "2009-01-25T06:40:03Z", "from" : { "type" : "user", "id" : "mndoci", "name" : "Deepak Singh" } } ], "date" : "2009-01-25T06:27:55Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/51c8687c270f40a4bfd69da48d102b80", "body" : "Pipes: Filter OpenWetWare Feed - http://pipes.yahoo.com/skoch3...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/oww/51c8687c/pipes-filter-openwetware-feed", "comments" : [ { "date" : "2009-02-05T09:55:13Z", "body" : "Steve, there is also a way of setting up a feed for a specific namespace at OWW. Have a look at the isisbio pages. Bill set this up a while back and we use it to pipe all of the changes on the wiki pages into the friendfeed room. That <startfeed/> creates a feed for all the subsidiary pages in the namespace ISISBio which you can see by pointing an RSS reader at http://openwetware.org/wiki...", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" }, "id" : "e/51c8687c270f40a4bfd69da48d102b80/c/204527598d4148448c2562ffc55a2c1b" }, { "date" : "2009-02-05T23:17:52Z", "body" : "Thanks, Cameron -- I didn't know about that. I think that looks good. The simple Pipe I created would be nice if you didn't want to add the <startfeed/> for whatever reason, or for other kinds of keyword feeding.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/51c8687c270f40a4bfd69da48d102b80/c/eb209dbd67974503bc4beaccfb5e75df" } ], "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2009-04-23T15:10:31Z", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" } }, { "date" : "2009-02-05T10:35:17Z", "from" : { "type" : "user", "id" : "ebola", "name" : "Maureen" } }, { "date" : "2009-02-05T09:52:11Z", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" } } ], "date" : "2009-02-05T04:41:37Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/a04ce3816fe34337b0a4b9cb31eefe28", "body" : "Can embed Google Docs spreadsheet in OWW pages now. - http://openwetware.org/wiki...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/oww/a04ce381/can-embed-google-docs-spreadsheet-in-oww-pages", "comments" : [ { "date" : "2009-04-15T05:49:01Z", "body" : "Anthony inspired Bill Flanagan to roll out some spreadsheet (and other docs) stuff he's been working on recently. The link is to a page in Anthony's notebook using the embedded Google spreadsheet. I also think Bill either has or will enable similar features for embedding content from uploaded excel, word, and pdfs? Not really sure, but I think the ability to use spreadsheets is a huge bonus for OWW.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/a04ce3816fe34337b0a4b9cb31eefe28/c/31fa5642c6f64617b98c8fba247d7044" }, { "date" : "2009-04-15T05:50:02Z", "body" : "There are some drawbacks still, I think -- for example, the data is at Google, not OWW, and I don't think Bill can access the data so it can be indexed and backed up at OWW. But maybe this problem can be solved in the future.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/a04ce3816fe34337b0a4b9cb31eefe28/c/8ddbbf83eeb0468aa2d495ca7325734f" }, { "date" : "2009-04-15T05:50:39Z", "body" : "See related entry in Anthony's friendfeed: http://friendfeed.com/e...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/a04ce3816fe34337b0a4b9cb31eefe28/c/23f5de611211411fbcd1fa4398182cd8" }, { "date" : "2009-04-15T06:02:37Z", "body" : "Also, Jean-Claude had a recent post related to automatic backup of Google spreadsheets and other things. I am lack too much understanding to comment, but it appears to me that all these things are related. See his post: http://friendfeed.com/e...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/a04ce3816fe34337b0a4b9cb31eefe28/c/0e79d4f83d424ff0a485e8373fa8fd32" } ], "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2010-02-08T23:45:50Z", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" } }, { "date" : "2009-04-16T05:36:33Z", "from" : { "type" : "user", "id" : "freesci", "name" : "Pawel Szczesny" } }, { "date" : "2009-04-15T07:55:41Z", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" } }, { "date" : "2009-04-15T06:36:41Z", "from" : { "type" : "user", "id" : "benjamintseng", "name" : "Benjamin Tseng" } }, { "date" : "2009-04-15T05:59:39Z", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" } } ], "date" : "2009-04-15T05:45:02Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/16d6c7a3aaa24d3984af823a310f194b", "body" : "Drew Endy's first blog post: State of the OWW | OpenWetWare Community - http://blog.openwetware.org/communi...", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/oww/16d6c7a3/drew-endy-first-blog-post-state-of-oww", "comments" : [ { "date" : "2009-06-12T16:27:26Z", "body" : "An excellent "state of the OWW" and call to action for all OWW users and potential users.", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/16d6c7a3aaa24d3984af823a310f194b/c/e0187c49d39044eead1d95f81b7d0352" }, { "date" : "2009-06-12T16:35:51Z", "body" : "An important discussion - where does it all go? And at the end of the day are we prepared to pay for it?", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" }, "id" : "e/16d6c7a3aaa24d3984af823a310f194b/c/269bd68986624af59ca34df73ce782c7" }, { "date" : "2009-06-13T02:05:50Z", "body" : "See also: http://friendfeed.com/openwet...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/16d6c7a3aaa24d3984af823a310f194b/c/df0933b36027427496ac4b3a52c9021a" }, { "date" : "2009-06-15T07:53:22Z", "body" : "Thinking...", "from" : { "type" : "user", "id" : "alethea", "name" : "Heather" }, "id" : "e/16d6c7a3aaa24d3984af823a310f194b/c/121ce1631a544112930b239b51110a39" } ], "to" : [ { "type" : "user", "id" : "stevekoch", "name" : "Steve's feed" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" }, { "type" : "group", "id" : "science-2-0", "name" : "Science 2.0" }, { "type" : "group", "id" : "the-life-scientists", "name" : "The Life Scientists" }, { "type" : "group", "id" : "kochlab", "name" : "Kochlab" } ], "likes" : [ { "date" : "2009-06-15T14:26:13Z", "from" : { "type" : "user", "id" : "aloisius", "name" : "Jordan M" } }, { "date" : "2009-06-15T07:53:12Z", "from" : { "type" : "user", "id" : "alethea", "name" : "Heather" } }, { "date" : "2009-06-13T09:59:28Z", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" } }, { "date" : "2009-06-13T06:15:46Z", "from" : { "type" : "user", "id" : "shwu", "name" : "Shirley Wu" } }, { "date" : "2009-06-12T18:50:40Z", "from" : { "type" : "user", "id" : "ruchira", "name" : "Ruchira S. Datta" } }, { "date" : "2009-06-12T16:51:07Z", "from" : { "type" : "user", "id" : "pedrobeltrao", "name" : "Pedro Beltrao" } }, { "date" : "2009-06-12T16:44:40Z", "from" : { "type" : "user", "id" : "sjcockell", "name" : "Simon Cockell" } }, { "date" : "2009-06-12T16:37:03Z", "from" : { "type" : "user", "id" : "michaelnielsen", "name" : "Michael Nielsen" } }, { "date" : "2009-06-12T16:35:27Z", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" } }, { "date" : "2009-06-12T16:28:56Z", "from" : { "type" : "user", "id" : "webmaven", "name" : "Michael R. Bernstein" } } ], "date" : "2009-06-12T16:27:26Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/a67883bece6e4eb8b9879f6c31c927a8", "body" : "If you're interested in Biophysical Society Annual Meeting 2010 #BPS2010 in San Francisco, I created a FF room http://friendfeed.com/biophys...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/kochlab/a67883be/if-you-re-interested-in-biophysical-society", "to" : [ { "type" : "user", "id" : "stevekoch", "name" : "Steve's feed" }, { "type" : "group", "id" : "kochlab", "name" : "Kochlab" }, { "type" : "group", "id" : "the-life-scientists", "name" : "The Life Scientists" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2010-02-06T19:32:41Z", "from" : { "type" : "user", "id" : "boudicca", "name" : "Lisa Green" } }, { "date" : "2009-08-20T14:05:12Z", "from" : { "type" : "user", "id" : "biehl", "name" : "Anders Norgaard" } } ], "date" : "2009-08-19T07:23:47Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/6dec4105d99e4f7596e4dc7b5261604f", "body" : "Do you know of any examples of Open Notebook data being fetched automatically into a data repository on a regular basis?", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "url" : "http://friendfeed.com/oww/6dec4105/do-you-know-of-any-examples-open-notebook-data", "comments" : [ { "date" : "2009-09-10T14:01:17Z", "body" : "I think Egon is working on something along those lines for the Solubility data. None of our data is structured enough to make this easy at the moment.", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" }, "id" : "e/6dec4105d99e4f7596e4dc7b5261604f/c/e576d021b6244c70b3e650c42b5d1780" }, { "date" : "2009-09-10T18:33:34Z", "body" : "Thanks, Cameron. I am currently back to the "What would science look like if it were invented today" draft ( http://en.wikiversity.org/wiki... ) and would like to mention such examples there, along with the exciting prospect of harvesting data repositories to put the data in context, as http://en.wikipedia.org/wiki... does it for Genes.", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/6dec4105d99e4f7596e4dc7b5261604f/c/9089425152f94a779eb975d1a8c4e78f" } ], "to" : [ { "type" : "user", "id" : "danielmietchen", "name" : "Daniel's feed" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2009-09-10T16:57:35Z", "from" : { "type" : "user", "id" : "paulsb", "private" : true, "name" : "Paul Bacchus" } }, { "date" : "2009-09-10T15:01:07Z", "from" : { "type" : "user", "id" : "claudiakoltzenburg", "name" : "Claudia Koltzenburg" } }, { "date" : "2009-09-10T14:01:23Z", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" } } ], "date" : "2009-09-10T13:57:00Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/9421ccf89100483998d229eb50856d85", "body" : "Model notebook, combo FriendFeed with MediaWiki (OpenWetWare) - http://openwetware.org/wiki...", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/science-2-0/9421ccf8/model-notebook-combo-friendfeed-with", "comments" : [ { "date" : "2010-01-30T03:48:26Z", "body" : "I have been thinking for several months that FriendFeed is very close to what I need for a lab notebook. This page is to help me think about that. The main thing missing at the moment (it seems) is just a way to filter FriendFeed stuff by date. There's also the issue that the wiki doesn't "know" the FriendFeed content, and so versioning stuff is lost. But seems to me many of the pieces are there.", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/1db3f737ce3041cfa894b0490fb849b0" }, { "date" : "2010-01-30T04:05:19Z", "body" : "One valid question would be: "is there a point to the wiki?" I'm thinking not a whole lot, right now I'm just using it as an easy way to place in a few iframes of the friend feed threads. A really advanced mindmap that I could drag and drop FriendFeed threads around, and then describe relationships between feeds would be very cool. Of course, I'm biased that way because I learned how mindmaps work last night and looked into them today.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/d93b0617269a4ad882ddfc58282186d9" }, { "date" : "2010-01-30T05:36:56Z", "body" : "Breakin' the law! I'm so cool. Here's some non-science for you: http://friendfeed.com/steveko...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/9461822a35f746098d43a876d4c82768" }, { "date" : "2010-01-30T06:40:00Z", "body" : "I would say that there is a point to the wiki. Mainly because you can embed video, use LaTeX, Google spreadsheets, etc. Plus the wiki markup allows for greater structure in a post (headings, links...). Now if we use the power of the wiki with the flexibility for posting things via Friendfeed, that's spectacular. The ability to post relevent conversations on Friendfeed to a notebook entry is pretty awesome. I actually can't wait to try this.", "via" : { "url" : "http://friendfeed.com/about/tools", "name" : "iPhone" }, "from" : { "type" : "user", "id" : "andymaloney", "name" : "Andy Maloney" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/1adee48f7ce54257b0553208ff40a0e6" }, { "date" : "2010-01-30T09:07:11Z", "body" : "I also like the wiki because I am more of a wet lab person, and it more resembles a lab notebook to me - way to paste in various pieces of information as Andy wrote. Will follow this with much interest.", "from" : { "type" : "user", "id" : "alethea", "name" : "Heather" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/563e1558bedf45d781a51db819456fd4" }, { "date" : "2010-01-30T10:54:54Z", "body" : "I've been using the wiki within our institutional VLE for over a year (giving up the paper notebooks was v. difficult!;) The flexibility is key: got to be able to post / upload anything. Am working on a "parts list" for diagrams that are used frequently (sequence maps, pcr primers etc) mostly generated spontaneously by students. Anybody know of an online source of such things?", "via" : { "url" : "http://www.nambu.com/", "name" : "Nambu" }, "from" : { "type" : "user", "id" : "richardbadge", "name" : "Richard Badge" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/9c329b5ca7e449059ea5c1939c98dad0" }, { "date" : "2010-02-11T15:31:28Z", "body" : "Ant also asked this question, "do you need OWW?" I think if OWW can transform to make this work, then it'd be a "yes," since it could be very flexible. I had to create this example page manually. The next version of OWW (or other VLE or whatever) needs to be able to create pages automatically. So, when I create a new gel photo it automatically goes in my "gels" section of that day's page. It's OK if I need to do some setup work, but I shouldn't have to manually do stuff every day.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/546f7f772f414014af4546115c2d6241" }, { "date" : "2010-02-11T17:49:16Z", "body" : "I do not think imagining a FF widget is too far off: http://openwetware.org/wiki... .", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/34d1d26fddc94f00a66703f0b09b3bd0" }, { "date" : "2010-02-11T21:19:31Z", "body" : "It's times like this I feel the lack of a DropBox API - but we do have a grant in to develop a really lightweight, "drop it in the appropriate folder and have it go to the right place" system. That could work with the MediaWiki API (or anything else) to enable a bit of this kind of thing. But agree with Richard, its nice if a system knows what to do with a particular file type, but the important thing is that you can upload anything at all.", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/7d12481b0f964eb3851af2c5653908ec" }, { "date" : "2010-02-12T01:43:19Z", "body" : "I think that it has all been mentioned already, but I just want to emphasize what Andy pointed out. The the wiki gives your information some structure, mostly in regards to non-notebook information. As great as the lab notebook format that the wiki provides is, as I've had less and less time during the past few months, it has become more annoying to manually upload files/enter entries for my notebook using the wiki, especially once I fall behind updating things. I've been using google docs instead and just keeping the files that I would've normally uploaded on my computer for now. In an ideal world, I'd like to work on a "cloud" that would keep all of my work stuff available to me at home without the use of VPN or a server (actually something in between using a lab network and a wiki). Sorry for the rant, this new FF capability is cool though :)", "from" : { "type" : "user", "id" : "ramalldf", "name" : "Diego" }, "id" : "e/9421ccf89100483998d229eb50856d85/c/7c5b1434479942faa02220d464e82f73" } ], "to" : [ { "type" : "user", "id" : "stevekoch", "name" : "Steve's feed" }, { "type" : "group", "id" : "science-2-0", "name" : "Science 2.0" }, { "type" : "group", "id" : "the-life-scientists", "name" : "The Life Scientists" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" }, { "type" : "group", "id" : "eresearch", "name" : "eResearch & ScholComm" } ], "likes" : [ { "date" : "2010-02-11T18:53:27Z", "from" : { "type" : "user", "id" : "bersenev", "name" : "Alexey" } }, { "date" : "2010-02-11T15:56:13Z", "from" : { "type" : "user", "id" : "tomtullius", "name" : "Tom Tullius" } }, { "date" : "2010-02-01T12:29:53Z", "from" : { "type" : "user", "id" : "graymills", "name" : "Peter Miller" } }, { "date" : "2010-02-01T11:55:35Z", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" } }, { "date" : "2010-01-30T21:32:14Z", "from" : { "type" : "user", "id" : "freesci", "name" : "Pawel Szczesny" } }, { "date" : "2010-01-30T20:25:27Z", "from" : { "type" : "user", "id" : "billhooker", "name" : "Bill Hooker" } }, { "date" : "2010-01-30T18:00:09Z", "from" : { "type" : "user", "id" : "msscha", "name" : "Mickey Schafer" } }, { "date" : "2010-01-30T10:49:27Z", "from" : { "type" : "user", "id" : "richardbadge", "name" : "Richard Badge" } }, { "date" : "2010-01-30T09:59:43Z", "from" : { "type" : "user", "id" : "scilib", "name" : "Richard Akerman" } }, { "date" : "2010-01-30T08:34:57Z", "from" : { "type" : "user", "id" : "alethea", "name" : "Heather" } }, { "date" : "2010-01-30T04:18:38Z", "from" : { "type" : "user", "id" : "imabonehead", "private" : true, "name" : "imabonehead" } }, { "date" : "2010-01-30T04:10:55Z", "from" : { "type" : "user", "id" : "ruchira", "name" : "Ruchira S. Datta" } } ], "date" : "2010-01-30T03:48:26Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/494128a2893e4bd2acac425b4e00518b", "body" : "More Open Notebook Science! Carl Boettiger, grad at UC-Davis. - http://openwetware.org/wiki...", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "url" : "http://friendfeed.com/science-2-0/494128a2/more-open-notebook-science-carl-boettiger-grad", "comments" : [ { "date" : "2010-02-05T19:20:24Z", "body" : "Has two notebooks so far, this one and also another, both using the wiki on OpenWetWare: http://openwetware.org/wiki...", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/fbb944e7f38441b98902dfb574bb4530" }, { "date" : "2010-02-05T19:21:24Z", "body" : "Here's Carl's friendfeed: http://friendfeed.com/cboettig", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/649fd6c8ab3f4c6d9d6984d2d3228e6b" }, { "date" : "2010-02-05T19:22:44Z", "body" : "Carl says that KochLab students' ONS on OWW partly inspired him to start his own open notebooks. That makes me happy! Props to Carl & Anthony, Larry, Andy, Brian, ...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/647d287ce8b543d797ac534612fc1ad8" }, { "date" : "2010-02-05T21:01:52Z", "body" : "One of us! One of us! :-) :-) This makes me very happy.", "from" : { "type" : "user", "id" : "billhooker", "name" : "Bill Hooker" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/1ca67ea797494d93978c5d71cbfd1a4a" }, { "date" : "2010-02-05T21:59:23Z", "body" : ""I'm an Open Scientist and this is what I do!" I agree with Bill. This makes me very happy!", "from" : { "type" : "user", "id" : "anthonysalvagno", "name" : "Anthony Salvagno" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/00ad6ca5bb2f46f6b0463bc408e4308d" }, { "date" : "2010-02-06T14:21:57Z", "body" : "nice! Are these examples of theoretical notebooks? http://en.wikipedia.org/wiki...", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/afe0bd084358440e9f4e2ed542aee570" }, { "date" : "2010-02-06T15:53:16Z", "body" : "I added his two notebooks under the theory section. As I understand it, it's theory + computational modeling. Computational modeling can be in either in my opinion--the kind of results generated are probably more like lab experiments than theory. So, probably there's need for far more than two categories. Plus, that section of notebooks examples is getting too big! That's a good thing, but I think a couple "examples" should be put in that section, and then the rest should be put in a new page, "Examples of ONS practitioners." Or at least, that section should be moved to the end of the article?", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/68661bf2db954075b7acbe1abcceae7e" }, { "date" : "2010-02-07T13:13:02Z", "body" : "Thanks for adding Steve. I think computational is more closely related to theoretical since there isn't a clear tradition of what constitutes an "experiment" and how to record it like there is in experimental sciences. I don't think the Wikipedia editors will allow the creation of a separate page just for examples of ONS but we certainly can put them at the end if some more examples get collected.", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/8a86cef98b174b93a7962a0936e86ed8" }, { "date" : "2010-02-07T16:58:37Z", "body" : "I'm surprised that wikipedia editors have been harassing you, Jean-Claude! I've started many articles of questionable significance and never had anyone mark them for deletion. (For example: http://en.wikipedia.org/wiki...) Someday I think the article would have to be changed to "notable open notebook science practitioners," but I don't see why we couldn't have a "List of open notebook science practitioners" page. There are thousands of pages like that. For example: http://en.wikipedia.org/wiki...", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/988cd28e08804ad98dd9c8be0d9213ee" }, { "date" : "2010-02-07T17:02:44Z", "body" : "Carl, you should pipe in on whether your computational work is more similar to theory or experiment! I think the whole spectrum of science is much harder to put into categories than Jean-Claude or I expect. I see computational as "experiment" often. For example, I collaborate with some people doing molecular dynamics (MD) simulations. It surprising how much like experiments it is. Perhaps the best example (and most amusing to me when I learned it) was the need for a "thermostat" in the simulation. The student spent a few weeks tweaking the MD software until he could get his thermostat working. I'd say recording that process, along with all the failed experiments (and the conditions that led to them) would be very valuable. Very much like what we'd like to do in our experiments. But it's probably be easier to capture the information for the computational stuff--so I'd expect those open notebooks to be excellent sooner than ours.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/54a9326944f047ebb57cbb715da68579" }, { "date" : "2010-02-07T18:20:44Z", "body" : "Steve - it was actually not that easy to get the ONS entry on Wikipedia to not be deleted or redirected - it took 2 tries and lots of documentation to appease the editors - see the discussion page. I guess you don't know how it will play out until you try.", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/c8407558cee94d438d39b70b6a96354f" }, { "date" : "2010-02-07T18:32:07Z", "body" : "Sounds like an overly-aggressive guy was obsessed with deleting your article? No rush for anything, but if you think it'd be better with a sub-page of practitioners, I'll create the page someday.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/c420da5c82fd404e926707be48698de4" }, { "date" : "2010-02-07T18:38:10Z", "body" : "Steve - I think it is actually much more difficult to capture the information for computational experiments because it is so easy to generate immense amounts of data. If every tweak is "an experiment" you would end up spending more time documenting what you do than actually doing work. When we did docking we did approach documenting it like a physical experiment so that there is enough information to reproduce (e.g. http://usefulchem.wikispaces.com/D-EXP01... ) but we didn't record every parameter tried. In a wet lab experiment the situation is much more clear cut - if you do something physically in the lab during an experiment you record it. This is a practice that is part of academia and industry - well defined enough that the "lab notebook" has a legal meaning in patent law.", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/02d47d6331a34b2487c88a82746ae878" }, { "date" : "2010-02-07T19:11:08Z", "body" : "Interesting, Jean-Claude. And I hadn't been thinking of the legal definition (and I also don't feel like thinking about that now :) ). The MD simulations I was thinking of actually took significant time on a supercomputer for each tweak (I think). So, that would be practical to record everything and treat it as an experiment. Clearly, though, as you say there are cases where it would be very difficult to capture everything. This is true in some experiments, too, though! For example I remember in the Collider Detector Facility (CDF) at Fermilab, the first round of data acquisition was all hardware and the job was to filter out 90% (or whatever fraction) of the data so that the bandwidth of the next steps would be sufficient. That seems like a clear example of too much experimental data to save. So, probably the spectrum of open notebook science shouldn't just be one-dimensional from theory to experiment. It seems like at least one more dimension is needed which describes how much information there is to capture.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/fbba7912ab354b0f83a39ddb3b20872d" }, { "date" : "2010-02-07T19:15:36Z", "body" : "And perhaps another dimension for how much tacit knowledge there is. I think tacit knowledge may be what I had in mind when I said computational science may be easier to do as ONS. Certainly there is tacit knowledge in computational science. But listening to John Hogenech at ScienceOnline2010, I learned that it's possible for one group to exactly replicate another group's computations, if they use Amazon Web Services as the platform. Or, Deepak pointed out Virtual Machines to me as a way of packaging a computational environment. So it seems easier to at least transfer some of the tacit knowledge. In a wetlab, it's still not possible to do that. So, maybe there're at least three dimensions on which to classify ONS: (1) experiment / theory, (2) volume of information, and (3) volume of tacit knowledge (or maybe ratio of tacit knowledge to explicit knowledge)", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/1eda8e01599d48ca8c0b616e147be298" }, { "date" : "2010-02-07T19:17:56Z", "body" : "For Andy's gliding motility assays in our lab, I'd rate it (1) solidly in experiment, (2) low/moderate amounts of information (GBs of image data), (3) moderate/high amounts of tacit knowledge. (Or tacit knowledge that is difficult to capture. Maybe that's what the 3rd dimension is: how difficult to capture the tacit knowledge)", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/01e7bfc210844a0ba7ff159c1b196759" }, { "date" : "2010-02-07T20:57:23Z", "body" : "Interesting discussion! In my mind they are both. In the phyologenetics notebook, I am trying to extend the theory of comparative methods beyond linear models. This field is moving very quickly, and it's no use to suggest new theory without providing software that implements it, or no one will be able to use it. I also find that saving all the data from all the runs I do can be prohibitive. If I want to repeat any simulation or run I describe in the notebook, I (or anyone else) can grab the code as it was that day from the subversion repository on google and rerun it. Still figuring out how to get the most out of this!", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/6d8df0b1e9ae4e4dba415679585a7ddd" }, { "date" : "2010-02-08T14:38:56Z", "body" : "The reason I mention the legal definition of a lab notebook is that it leads to an expectation in the scientific community that students will be trained to record their experiments in a fairly consistent way. Perhaps I have the wrong impression here but it seems that there is not a standard way to record computational/theoretical work. [In fact as a postdoc I wanted to change the format of my lab notebook and my supervisor refused because it was not consistent with the requirements of our Research Office]. However, in general I think the acid test for a good notebook is whether an article or patent can be written from the records without significant interaction with the student/researcher who kept it. If the record keeping is so bad that one can't tell what happened in the experiment then the work is wasted. Unfortunately it isn't uncommon for students to repeat experiments from students who kept poor notes and left the lab.", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/89ad7528242c4fe6af56e888adee3cbd" }, { "date" : "2010-02-08T14:43:49Z", "body" : "Carl - one of the benefits I'm finding from the researchers who keep Open Notebooks is learning how science is done in different fields and different groups. This is something that has traditionally been difficult to assess because notebooks are traditionally very private. Over time we're gathering data that will prove handy for discovering how the scientific process actually works - as opposed to the ideal of hypothesis -> experiment design and execution -> evaluation which is widely taught.", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/e25821f4473a497396c8fb2ffe959bb4" }, { "date" : "2010-02-08T18:02:53Z", "body" : "Jean-Claude, that's an excellent point. I've also found that most of my colleagues in wet labs are taught to keep lab notebooks in a rather precise way. I know of only a few theorists in my department who keep any kind of regular notebook, and I've never had that kind of instruction or even encouragement. In computational sciences I'm surprised how few scientists use version management like subversion, which maintains a revision log, etc, for their codes. It will be interesting to see what feedback & suggestions I get on how to keep a notebook effectively.", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/7c43664bf50e4e8e91eadd7a229fbf74" }, { "date" : "2010-02-08T20:28:06Z", "body" : "Thanks for the feedback Carl - it will be interesting to see what response you get", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/494128a2893e4bd2acac425b4e00518b/c/b43bd571412644a4aeb1cfbdb4ae6fac" } ], "to" : [ { "type" : "user", "id" : "stevekoch", "name" : "Steve's feed" }, { "type" : "group", "id" : "science-2-0", "name" : "Science 2.0" }, { "type" : "group", "id" : "the-life-scientists", "name" : "The Life Scientists" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2010-02-10T10:07:47Z", "from" : { "type" : "user", "id" : "alethea", "name" : "Heather" } }, { "date" : "2010-02-08T16:08:57Z", "from" : { "type" : "user", "id" : "msscha", "name" : "Mickey Schafer" } }, { "date" : "2010-02-07T18:30:05Z", "from" : { "type" : "user", "id" : "imabonehead", "private" : true, "name" : "imabonehead" } }, { "date" : "2010-02-06T19:48:13Z", "from" : { "type" : "user", "id" : "graymills", "name" : "Peter Miller" } }, { "date" : "2010-02-06T18:26:48Z", "from" : { "type" : "user", "id" : "pfanderson", "name" : "Patricia F. Anderson" } }, { "date" : "2010-02-06T15:25:30Z", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" } }, { "date" : "2010-02-06T14:23:09Z", "from" : { "type" : "user", "id" : "band", "name" : "Bill Anderson" } }, { "date" : "2010-02-06T14:20:14Z", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" } }, { "date" : "2010-02-06T11:11:24Z", "from" : { "type" : "user", "id" : "paulsb", "private" : true, "name" : "Paul Bacchus" } }, { "date" : "2010-02-06T05:56:58Z", "from" : { "type" : "user", "id" : "mrgunn", "name" : "Mr. Gunn" } }, { "date" : "2010-02-05T21:00:22Z", "from" : { "type" : "user", "id" : "billhooker", "name" : "Bill Hooker" } }, { "date" : "2010-02-05T19:45:51Z", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" } }, { "date" : "2010-02-05T19:44:41Z", "from" : { "type" : "user", "id" : "michaelnielsen", "name" : "Michael Nielsen" } }, { "date" : "2010-02-05T19:31:15Z", "from" : { "type" : "user", "id" : "treeoflife", "name" : "Jonathan Eisen" } } ], "date" : "2010-02-05T19:20:24Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad", "body" : "Moving more of my lab notes to OpenWetWare. Problem: Most previous notes contain screenshots of copyrighted materials. How to deal with that? Notebook much less useful without these.", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "url" : "http://friendfeed.com/science-2-0/64cdcfe1/moving-more-of-my-lab-notes-to-openwetware", "comments" : [ { "date" : "2010-02-08T13:20:55Z", "body" : "What are they screenshots of? If it's shots of analysis software I don't think anyone is too likely to go after you. Small snippets of things should be ok as well. Your bigger problem may actually be uploading lots of images...", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/dfaea14345454abd9cf0ee6a034b06b7" }, { "date" : "2010-02-08T20:27:31Z", "body" : "The screenshots are of basically anything you can find in papers - figures, tables, equations, quotes, text or combinations thereof. Several hundreds of them, named in a way that scripts could handle them. Is bot upload allowed on OWW?", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/6a10ce45266541adaba1c78ea9a8310b" }, { "date" : "2010-02-08T20:47:43Z", "body" : "@Daniel, no, the OWW API ( http://openwetware.org/api.php . ) is read only", "from" : { "type" : "user", "id" : "yokofakun", "name" : "Pierre Lindenbaum" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/a80cab922b064517b6de105881fcbe52" }, { "date" : "2010-02-08T21:03:57Z", "body" : "Thanks, Pierre. That's not what I had hoped for, but it shall facilitate further planning. Perhaps it's best just to let the current projects run out on their old platform and to start new ones in the open (if the coworkers agree, which is not always a given).", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/a8198dba921e40c3a23fad756f68a1b1" }, { "date" : "2010-02-08T21:13:45Z", "body" : "Well, may be you can ask OWW to turn on the write API. ( http://www.mediawiki.org/wiki... )", "from" : { "type" : "user", "id" : "yokofakun", "name" : "Pierre Lindenbaum" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/b20d4a34f8d84aa9acb8d46d4406c01a" }, { "date" : "2010-02-08T23:02:58Z", "body" : "Thanks, will give it a try.", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/c4fce70eb47f4727a46dd4716c25f3c7" }, { "date" : "2010-02-09T01:51:41Z", "body" : "Daniel - when we refer to other papers in our notebooks we link to the DOI. For ILL requests we upload them to a password protected server where all of our collaborators know the password. For full non-OA papers I don't think we have a choice on the matter. But for single figures or quotes I think you can make a good case for fair use and make them public. We do that routinely. You are not trying to sell copyrighted material so I think the worst case would be the publisher finding your image and requesting you to take it down - and we have not come across that problem. Good luck with getting your co-workers to agree!", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/1d80a4426a8b4f4ebc4247743ffcab9d" }, { "date" : "2010-02-09T13:16:04Z", "body" : "I am now uploading some of the files to flickr to see whether that could be an alternative.", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/b82b38779ca94272af0f33d247c1a2d7" }, { "date" : "2010-02-09T14:40:59Z", "body" : "We have used Flickr - but usually just upload images to Wikispaces since they automatically get included in the archive when doing an HTML export of the entire wiki. Does OWW have export options for back-ups?", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/bf3b90215c644f4da6123d2a34ad8fa1" }, { "date" : "2010-02-09T14:45:19Z", "body" : "I agree if you have small bits you can claim fair use, especially if you are using the material for academic purposes. You can also alter an image, graph, or figure and attribute it as an adaptation from the original with a link it it.", "from" : { "type" : "user", "id" : "eabrown25", "name" : "Elizabeth Brown" }, "id" : "e/64cdcfe1a4ec49d1adfeffeffc2ff6ad/c/c75d7a381f2340d0afedb4af0faf5387" } ], "to" : [ { "type" : "user", "id" : "danielmietchen", "name" : "Daniel's feed" }, { "type" : "group", "id" : "science-2-0", "name" : "Science 2.0" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2010-02-09T01:43:15Z", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" } } ], "date" : "2010-02-08T12:57:29Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/904424cccfe84291a7ce7a481407f64b", "body" : "Can someone explain to me how the stats counter at the bottom of the OpenWetWare page works? Is it total visits or unique ips? Is there any way to get more detailed stats (i.e. like google analytics for a webpage?) I think it would be interesting to know how people come across my notebook, from where, etc.", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "url" : "http://friendfeed.com/oww/904424cc/can-someone-explain-to-me-how-stats-counter-at", "comments" : [ { "date" : "2010-02-09T09:22:49Z", "body" : "I guess it is the count of visits ( http://www.mediawiki.org/wiki... ). An extension for Google analytics is available: http://www.mediawiki.org/wiki...", "from" : { "type" : "user", "id" : "yokofakun", "name" : "Pierre Lindenbaum" }, "id" : "e/904424cccfe84291a7ce7a481407f64b/c/346568ba785244d29b65e0f76775bf35" }, { "date" : "2010-02-09T09:29:16Z", "body" : "Looks like the OpenWetWare maintainers would have to install the google analytics extension first?", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/904424cccfe84291a7ce7a481407f64b/c/3c3f7f19a7704e57a8b0028984f3b817" }, { "date" : "2010-02-09T09:33:17Z", "body" : "Installing an extension shouldn't be a problem. OWW already contains many extensions http://openwetware.org/wiki...", "from" : { "type" : "user", "id" : "yokofakun", "name" : "Pierre Lindenbaum" }, "id" : "e/904424cccfe84291a7ce7a481407f64b/c/db8734ccb0e8472a8f4b631a18a6deff" }, { "date" : "2010-03-08T23:41:30Z", "body" : "Google Analytics is good for long term tracking. We also use Sitemeter, which is a handy way of letting anyone publicly track the last 100 visitors and seeing the keywords they used (hit by referrals from the sitemeter icon in the nav bar for example http://onschallenge.wikispaces.com/ )", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/904424cccfe84291a7ce7a481407f64b/c/372b5f1607e744358acd2e1ef03014d8" } ], "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "date" : "2010-02-09T09:13:10Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/b44ce050372e4620a8f2d1bee0e6b028", "body" : "Working with some other students to start an Open Science group at UC Davis to help raise awareness, share tools, build community and pressure for more open science on campus. Anyone know of such groups elsewhere that could be a model? Anyone have experience doing so?", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "url" : "http://friendfeed.com/sciencecommons/b44ce050/working-with-some-other-students-to-start-open", "comments" : [ { "date" : "2010-02-23T21:53:25Z", "body" : "UC Davis has an excellent group of science librarians (at least in the physical sciences - don't know the bio folks individually) - you should e-mail them and ask for help. You could start by e-mailing: pse@lib.ucdavis.edu", "from" : { "type" : "user", "id" : "cpikas", "name" : "Christina Pikas" }, "id" : "e/b44ce050372e4620a8f2d1bee0e6b028/c/ab3c0aa6ec574692bd1a6ad936ce1dae" }, { "date" : "2010-02-23T23:21:07Z", "body" : "I think the people in the groups of Jean-Claude Bradley, Matthew Todd or Steve Koch would be a good pool to dive in.", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/b44ce050372e4620a8f2d1bee0e6b028/c/b34c18cfefa746e7b9c1ad15c321aa50" }, { "date" : "2010-02-24T04:53:27Z", "body" : "Thanks for the mention, Daniel. Carl, check out The Synaptic Leap for our current project. http://www.thesynapticleap.org/schisto...", "from" : { "type" : "user", "id" : "mattodd", "name" : "Matthew Todd" }, "id" : "e/b44ce050372e4620a8f2d1bee0e6b028/c/6427b85c5043486da38664a04b08c63e" }, { "date" : "2010-02-24T05:04:42Z", "body" : "Matthew, that looks excellent. I remember seeing that in Nature news earlier this month! Great to see the website for the project. Will be a good example to share with other students.", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/b44ce050372e4620a8f2d1bee0e6b028/c/d2d143d0e2b1471faf9948cca64ff54e" }, { "date" : "2010-03-07T17:12:01Z", "body" : "Carl, I don't have a clear vision of what you should do ... but I agree with Daniel that connecting with students elsewhere would be great. Let me know if you want to get in touch with people in our lab.", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" }, "id" : "e/b44ce050372e4620a8f2d1bee0e6b028/c/cfa68513a2754d6c9863edb3ebe0dbb8" }, { "date" : "2010-03-08T16:19:57Z", "body" : "I'm not sure if you are talking about students in research or teaching labs but Steve has great examples of both. I have more experience with students in research labs.and we can both recommend tools.", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/b44ce050372e4620a8f2d1bee0e6b028/c/9eaf08b0f6f7451085115ef56655b8f8" }, { "date" : "2010-03-08T21:27:36Z", "body" : "Really aiming to organize students, staff, faculty across campus to promote an on-campus dialog about open science, similar to the on-line dialog that happens here. Our goals are to share tools, build community and advocate/promote more open science. We're getting underway now: http://openwetware.org/wiki...", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/b44ce050372e4620a8f2d1bee0e6b028/c/d0abab27e1314845b8788b02d7f4815b" }, { "date" : "2010-03-08T23:45:29Z", "body" : "Carl, if you are using OWW Steve is your man. If you are going to be serving a group of users you might want to consider automatically archiving their datasets. A very convenient way of hosting Open Data is through Google Spreadsheets. Andrew Lang has written some code to automatically archive these as Excel by crawling through HTML pages. See for more info: http://usefulchem.blogspot.com/2010...", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/b44ce050372e4620a8f2d1bee0e6b028/c/972d6ccc4d4a4f37871a974e5b2fd143" } ], "to" : [ { "type" : "user", "id" : "cboettig", "name" : "Carl's feed" }, { "type" : "group", "id" : "sciencecommons", "name" : "Science Commons" }, { "type" : "group", "id" : "scienceonline2012", "name" : "ScienceOnline2012" }, { "type" : "group", "id" : "science-2-0", "name" : "Science 2.0" }, { "type" : "group", "id" : "the-life-scientists", "name" : "The Life Scientists" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2010-03-09T07:29:55Z", "from" : { "type" : "user", "id" : "suelibrarian", "private" : true, "name" : "suelibrarian" } }, { "date" : "2010-03-09T00:14:16Z", "from" : { "type" : "user", "id" : "gezelter", "name" : "Dan Gezelter" } }, { "date" : "2010-03-08T17:31:26Z", "from" : { "type" : "user", "id" : "researchremix", "name" : "Heather Piwowar" } }, { "date" : "2010-03-08T16:53:34Z", "from" : { "type" : "user", "id" : "krash63", "private" : true, "name" : "Kristi Miller Durazo" } }, { "date" : "2010-03-08T16:51:01Z", "from" : { "type" : "user", "id" : "attilacsordas", "name" : "Attila Csordas" } }, { "date" : "2010-03-08T16:21:27Z", "from" : { "type" : "user", "id" : "khalidmirza", "name" : "Khalid Mirza" } }, { "date" : "2010-03-08T16:16:35Z", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" } }, { "date" : "2010-03-07T17:10:30Z", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" } }, { "date" : "2010-02-24T06:17:19Z", "from" : { "type" : "user", "id" : "mrgunn", "name" : "Mr. Gunn" } }, { "date" : "2010-02-24T06:00:02Z", "from" : { "type" : "user", "id" : "brembs", "name" : "Björn Brembs" } }, { "date" : "2010-02-24T04:53:32Z", "from" : { "type" : "user", "id" : "mattodd", "name" : "Matthew Todd" } }, { "date" : "2010-02-24T01:42:01Z", "from" : { "type" : "user", "id" : "dgaston", "name" : "Daniel Gaston" } }, { "date" : "2010-02-24T01:03:29Z", "from" : { "type" : "user", "id" : "scimatic", "name" : "Jamie McQuay" } }, { "date" : "2010-02-23T23:56:14Z", "from" : { "type" : "user", "id" : "billhooker", "name" : "Bill Hooker" } }, { "date" : "2010-02-23T23:20:54Z", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" } }, { "date" : "2010-02-23T22:44:47Z", "from" : { "type" : "user", "id" : "plausibleaccuracy", "name" : "Jason Winget" } }, { "date" : "2010-02-23T21:58:03Z", "from" : { "type" : "user", "id" : "cpikas", "name" : "Christina Pikas" } } ], "date" : "2010-02-23T21:20:56Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/2a4af18d6f02454aa6e5b65db896ae5c", "body" : "<biblio> error at OWW: Where to report such things? Example: http://openwetware.org/wiki... (currently gives "Error fetching PMID 19123244", while other papers seem unaffected).", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "url" : "http://friendfeed.com/oww/2a4af18d/biblio-error-at-oww-where-to-report-such-things", "comments" : [ { "date" : "2010-04-29T09:46:52Z", "body" : "Even worse at http://openwetware.org/wiki... , where only one displays properly. Both pages had no problems last time I checked.", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/2a4af18d6f02454aa6e5b65db896ae5c/c/b888433991d14a8da4c44edb6146b9aa" }, { "date" : "2010-04-29T09:50:05Z", "body" : "send a mail to Bill Flanagan http://openwetware.org/wiki...", "from" : { "type" : "user", "id" : "yokofakun", "name" : "Pierre Lindenbaum" }, "id" : "e/2a4af18d6f02454aa6e5b65db896ae5c/c/8b6776485d434da9b67699f602a8fb8f" }, { "date" : "2010-04-29T10:08:51Z", "body" : "Done - thanks!", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/2a4af18d6f02454aa6e5b65db896ae5c/c/acdd290683e24c1abdbc00564fc42873" } ], "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "date" : "2010-04-29T09:46:23Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/7079cc6f63db412fb697c72dc1d445a0", "body" : "First go at a brainstorming session from this morning. http://prezi.com/0qg1e6f... Any comments more than welcome!", "from" : { "type" : "user", "id" : "kubke", "name" : "Kubke" }, "url" : "http://friendfeed.com/oww/7079cc6f/first-go-at-brainstorming-session-from-this", "comments" : [ { "date" : "2010-07-10T08:09:00Z", "body" : ""There is no Prezi on this address, or it has not been published."", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/7079cc6f63db412fb697c72dc1d445a0/c/cc2f3fefa04b4029923d81511d6cce03" }, { "date" : "2010-07-10T12:28:32Z", "body" : "Oops... forgot that the default was 'private'. It is public now :)", "from" : { "type" : "user", "id" : "kubke", "name" : "Kubke" }, "id" : "e/7079cc6f63db412fb697c72dc1d445a0/c/df827637385040f69930bb3e448c7e2f" }, { "date" : "2010-07-12T14:32:34Z", "body" : "Nothing happens when you click on the play/next slide button.", "from" : { "type" : "user", "id" : "maverickny", "name" : "Sally Church" }, "id" : "e/7079cc6f63db412fb697c72dc1d445a0/c/2ab658cb7e2f49c1ab172b1542a9a9ef" }, { "date" : "2010-07-12T21:24:59Z", "body" : "OK, I will try to put this somewhere else. Sorry about that....", "from" : { "type" : "user", "id" : "kubke", "name" : "Kubke" }, "id" : "e/7079cc6f63db412fb697c72dc1d445a0/c/491e6635803f42dfb46b3db71f33c474" }, { "date" : "2011-04-06T10:12:07Z", "body" : "Redone http://wikieducator.org/images...", "from" : { "type" : "user", "id" : "kubke", "name" : "Kubke" }, "id" : "e/7079cc6f63db412fb697c72dc1d445a0/c/0422bc89d1ff4d0da7542c93cad9ceaf" }, { "date" : "2011-04-06T13:27:57Z", "body" : "maybe link society and policy with a double arrow?", "from" : { "type" : "user", "id" : "claudiakoltzenburg", "name" : "Claudia Koltzenburg" }, "id" : "e/7079cc6f63db412fb697c72dc1d445a0/c/f6f3e7551f53422191bf38a328fb9cc7" }, { "date" : "2011-04-06T13:31:44Z", "body" : "I thought about it.. but does society influence policy directly or through their elected representatives? (policy has to be gov mediated, doesn't it?)", "from" : { "type" : "user", "id" : "kubke", "name" : "Kubke" }, "id" : "e/7079cc6f63db412fb697c72dc1d445a0/c/2dd8f957cf3547c9930e993c0e63f214" }, { "date" : "2011-04-06T13:35:25Z", "body" : "But - perhaps there should be arrows from society to education (parents are on governing boards), to health (hospital volunteering, red cross) and to science (citizen science) (updated)", "from" : { "type" : "user", "id" : "kubke", "name" : "Kubke" }, "id" : "e/7079cc6f63db412fb697c72dc1d445a0/c/381c43b98e1a4d219b6ae9ae1482f67c" } ], "to" : [ { "type" : "user", "id" : "kubke", "name" : "Kubke's feed" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" }, { "type" : "group", "id" : "science-2-0", "name" : "Science 2.0" }, { "type" : "group", "id" : "future-of-education", "name" : "Future of Education" }, { "type" : "group", "id" : "the-life-scientists", "name" : "The Life Scientists" } ], "date" : "2010-07-10T05:42:43Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/0f6575ddc2714ad8850b7ebbf344d9ff", "body" : "OpenWetWare - MediaWiki Widgets - http://www.mediawikiwidgets.org/OpenWet...", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "url" : "http://friendfeed.com/oww/0f6575dd/openwetware-mediawiki-widgets", "comments" : [ { "date" : "2010-08-17T13:01:32Z", "body" : ""This widget allows you to embed OpenWetWare pages on your wiki page."", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/0f6575ddc2714ad8850b7ebbf344d9ff/c/bab2984b4b844d2cadea6bceef5b30e3" }, { "date" : "2010-08-18T23:29:47Z", "body" : "Just wanted to play a bit more with it, but OWW is down right now.", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/0f6575ddc2714ad8850b7ebbf344d9ff/c/12f5d586194c450887ed8ee61141b2a3" }, { "date" : "2010-08-19T23:45:34Z", "body" : "OpenWetWare is back!", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" }, "id" : "e/0f6575ddc2714ad8850b7ebbf344d9ff/c/d224ea67f60f448e9a8d2224941a2096" } ], "to" : [ { "type" : "user", "id" : "danielmietchen", "name" : "Daniel's feed" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" }, { "type" : "group", "id" : "scholarly-wikis", "name" : "Scholarly wikis" } ], "likes" : [ { "date" : "2010-08-17T13:13:24Z", "from" : { "type" : "user", "id" : "yokofakun", "name" : "Pierre Lindenbaum" } } ], "date" : "2010-08-17T13:01:32Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/3adcbac67dab409bb5dab59866c30a13", "body" : "OpenWetWare tips and reflections. Comments welcome. http://www.openwetware.org/wiki...", "from" : { "type" : "user", "id" : "researchremix", "name" : "Heather Piwowar" }, "url" : "http://friendfeed.com/oww/3adcbac6/openwetware-tips-and-reflections-comments", "comments" : [ { "date" : "2010-08-18T19:56:14Z", "body" : "Great review, I agree with both the strengths and weaknesses you've listed. What's troubled me most is (a) the full-text search functions don't seem to completely index my notebook, (b) Categories just aren't sufficient for tagging, and (b) offline updates syncing doesn't work (despite trying the mediawiki app) . The best features are the community (though small), calendar, embedding, and template format (cover page, summary, updates).", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/3adcbac67dab409bb5dab59866c30a13/c/54dd828890fd4b12856f6e985172fecb" } ], "to" : [ { "type" : "user", "id" : "researchremix", "name" : "Heather's feed" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2010-08-23T15:57:58Z", "from" : { "type" : "user", "id" : "pampel1", "name" : "Heinz Pampel" } }, { "date" : "2010-08-18T21:12:48Z", "from" : { "type" : "user", "id" : "kubke", "name" : "Kubke" } }, { "date" : "2010-08-18T19:49:44Z", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" } } ], "date" : "2010-08-18T19:31:58Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/e5057a549af34d5e902c941a19f6473d", "body" : "Yikes, is openwetware.org down? Looks like it is: http://downforeveryoneorjustme.com/openwet...", "from" : { "type" : "user", "id" : "researchremix", "name" : "Heather Piwowar" }, "url" : "http://friendfeed.com/oww/e5057a54/yikes-is-openwetware-org-down-looks-like-it", "comments" : [ { "date" : "2010-08-18T20:40:11Z", "body" : "and I was about to comment a tool for at least downloading openwetware sites for working offline, but of course I've forgotten the name and it's written in my notebook! hmm.. seriously considering migrating my lab notebooks github's updated wiki, hope those 300mb are truly a soft limit...", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/e5057a549af34d5e902c941a19f6473d/c/fa77a5acb83a476dbe41518a7a9c99bc" }, { "date" : "2010-08-18T20:53:54Z", "body" : "yup, I've started an open notebook there and it is working really well so far. I miss the OWW embedding though!", "from" : { "type" : "user", "id" : "researchremix", "name" : "Heather Piwowar" }, "id" : "e/e5057a549af34d5e902c941a19f6473d/c/a298c5251edc46a7b80205319464f52f" }, { "date" : "2010-08-18T21:10:01Z", "body" : "neat. Embedding seems to work for me: http://wiki.github.com/cboetti...", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/e5057a549af34d5e902c941a19f6473d/c/378a924f8c3749f28fbac883e67ad7cd" }, { "date" : "2010-08-18T21:16:39Z", "body" : "No such luck for me on my test page here http://github.com/hpiwowa... I cut and paste your code. It looks like you haven't upgraded your wiki yet to the git-backed rewerite? I wonder if that would make a difference? Or am I just doing something silly wrong?", "from" : { "type" : "user", "id" : "researchremix", "name" : "Heather Piwowar" }, "id" : "e/e5057a549af34d5e902c941a19f6473d/c/f84125d9033340d28aaa525381a2e515" }, { "date" : "2010-08-18T21:27:38Z", "body" : "hmm, no, realized i hadn't upgraded that one. hmm", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/e5057a549af34d5e902c941a19f6473d/c/f3b58936e630457f86d6d1dc97b45c98" } ], "to" : [ { "type" : "user", "id" : "researchremix", "name" : "Heather's feed" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2010-08-19T15:25:48Z", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" } } ], "date" : "2010-08-18T20:04:56Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/a40f65e185334628b027c9f85036a7d2", "body" : "Fwd: Really need openwetware back up! Drew Endy is working on it... time to start keeping a local clone? (via http://friendfeed.com/cboetti...)", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "url" : "http://friendfeed.com/oww/a40f65e1/fwd-really-need-openwetware-back-up-drew-endy-is", "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "date" : "2010-08-19T17:31:31Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/7d66ccd6095f454cbddfdf9a7aac5f25", "body" : "OpenWetWare back up!", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "url" : "http://friendfeed.com/oww/7d66ccd6/openwetware-back-up", "to" : [ { "type" : "user", "id" : "cboettig", "name" : "Carl's feed" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2010-08-19T18:42:07Z", "from" : { "type" : "user", "id" : "researchremix", "name" : "Heather Piwowar" } } ], "date" : "2010-08-19T18:25:29Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/e9d9b6addc474337ab1e65b1ef63e949", "body" : "I'm looking for a good solution to upload figures into my open lab notebook. Need fast, many photo, automated / scriptable uploading, permanent hosting, with searching/tags/comments. Trying photobucket: http://openwetware.org/wiki... Thoughts?", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "url" : "http://friendfeed.com/science-2-0/e9d9b6ad/i-m-looking-for-good-solution-to-upload-figures", "comments" : [ { "date" : "2010-08-30T19:04:13Z", "body" : "I think ideally I would run a script which would run some code which generates a png figure, pushes the photo to the host site under a given album/tags and a link to the version of the code that created the figure on the project's github site. Since the codes take a long time to run, simply having the code version is no longer sufficient for me.", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/e9d9b6addc474337ab1e65b1ef63e949/c/e62f6d5af4604d87951c6def53e6f5f0" }, { "date" : "2010-08-30T19:21:04Z", "body" : "Have you considered the possibility of using Flickr to host the photos? They have an API, are quite inexpensive and I know that there is/was a plugin to add Flickr images easily into OWW (mediawiki).", "from" : { "type" : "user", "id" : "rvidal", "name" : "Ricardo Vidal" }, "id" : "e/e9d9b6addc474337ab1e65b1ef63e949/c/36b0e32c659947dcb3b1f7a029b6fb9a" }, { "date" : "2010-08-30T19:27:40Z", "body" : "Yup, Flickr seems very promising since there's lots of development around it. Do I need to buy a subscription to make sure the uploads are permanent? Think I'll give it a try...", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/e9d9b6addc474337ab1e65b1ef63e949/c/2814c3af84ba4ae5ad2ca95f30d27202" }, { "date" : "2010-08-30T19:57:34Z", "body" : "No, all uploads are permanent and I believe you can "display" up to 200 images for free. The last 200 are always visible and nothing is lost. If you pay the $24 USD/year, all images become public/visible again.", "from" : { "type" : "user", "id" : "rvidal", "name" : "Ricardo Vidal" }, "id" : "e/e9d9b6addc474337ab1e65b1ef63e949/c/5da1a835461e4544837d4be60a9cf58d" }, { "date" : "2010-08-30T23:15:10Z", "body" : "Flickr seems to be a nice solution. With one command-line call I can have a full slideshow of results embedded into the notebook! http://openwetware.org/wiki... Each image can collect comments and other tags and be organized into groups. the command-line upload also doesn't seem to spam my FF/twitter feed even though I added flickr to FF. guess that's a good thing.", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/e9d9b6addc474337ab1e65b1ef63e949/c/cb39fe5ed7434f9f814115e71f99ea7f" } ], "to" : [ { "type" : "group", "id" : "science-2-0", "name" : "Science 2.0" }, { "type" : "group", "id" : "the-life-scientists", "name" : "The Life Scientists" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" }, { "type" : "group", "id" : "sciencecommons", "name" : "Science Commons" } ], "likes" : [ { "date" : "2010-08-31T14:36:50Z", "from" : { "type" : "user", "id" : "paulsb", "private" : true, "name" : "Paul Bacchus" } }, { "date" : "2010-08-31T00:55:31Z", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" } }, { "date" : "2010-08-30T20:31:31Z", "from" : { "type" : "user", "id" : "researchremix", "name" : "Heather Piwowar" } }, { "date" : "2010-08-30T20:08:13Z", "from" : { "type" : "user", "id" : "gregtyrelle", "private" : true, "name" : "Greg Tyrelle" } }, { "date" : "2010-08-30T19:21:13Z", "from" : { "type" : "user", "id" : "rvidal", "name" : "Ricardo Vidal" } }, { "date" : "2010-08-30T19:16:05Z", "from" : { "type" : "user", "id" : "yokofakun", "name" : "Pierre Lindenbaum" } }, { "date" : "2010-08-30T19:03:59Z", "from" : { "type" : "user", "id" : "egonw", "name" : "Egon Willighagen" } } ], "date" : "2010-08-30T18:57:48Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/4ec53cbf129a488a9fc22672a2ccdbf1", "body" : "Welcome to my Lab Notebook Carl Boettiger - http://www.carlboettiger.info/archive...", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "thumbnails" : [ { "url" : "http://m.friendfeed-media.com/f0fcbf940cd42b71e38a1c64b6ed30c30a76ee95", "width" : 300, "link" : "http://www.carlboettiger.info/archives/211", "height" : 123 } ], "url" : "http://friendfeed.com/science-2-0/4ec53cbf/welcome-to-my-lab-notebook-carl-boettiger", "comments" : [ { "date" : "2010-11-08T03:22:56Z", "body" : "I've written a post as an introduction to my open lab notebook, explaining how I view it and how it's organized and integrated with my github, flickr, and mendeley accounts. Still figuring things out, but think I've learned a lot about notebook workflow over the past 6 months. Feedback welcome!", "via" : { "url" : "http://friendfeed.com/share/bookmarklet", "name" : "Bookmarklet" }, "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "id" : "e/4ec53cbf129a488a9fc22672a2ccdbf1/c/cd641105864744519691f3371a29c4c2" }, { "date" : "2010-11-08T14:41:59Z", "body" : "Awesome explanation of what you are doing with ONS!", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" }, "id" : "e/4ec53cbf129a488a9fc22672a2ccdbf1/c/1dda34c17e9e47ccb077e0923eb232ed" } ], "to" : [ { "type" : "user", "id" : "cboettig", "name" : "Carl's feed" }, { "type" : "group", "id" : "science-2-0", "name" : "Science 2.0" }, { "type" : "group", "id" : "the-life-scientists", "name" : "The Life Scientists" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" }, { "type" : "group", "id" : "scienceonline2012", "name" : "ScienceOnline2012" } ], "likes" : [ { "date" : "2010-12-06T00:21:26Z", "from" : { "type" : "user", "id" : "kubke", "name" : "Kubke" } }, { "date" : "2010-11-25T00:01:52Z", "from" : { "type" : "user", "id" : "pfanderson", "name" : "Patricia F. Anderson" } }, { "date" : "2010-11-18T09:10:27Z", "from" : { "type" : "user", "id" : "stevekoch", "name" : "Steve Koch" } }, { "date" : "2010-11-14T18:18:16Z", "from" : { "type" : "user", "id" : "byzia", "name" : "Piotr Byzia" } }, { "date" : "2010-11-12T10:21:50Z", "from" : { "type" : "user", "id" : "mrvaidya", "name" : "Gaurav Vaidya" } }, { "date" : "2010-11-11T23:17:36Z", "from" : { "type" : "user", "id" : "shwu", "name" : "Shirley Wu" } }, { "date" : "2010-11-09T07:02:48Z", "from" : { "type" : "user", "id" : "yarikson", "name" : "Yaroslav Nikolaev" } }, { "date" : "2010-11-08T21:19:04Z", "from" : { "type" : "user", "id" : "researchremix", "name" : "Heather Piwowar" } }, { "date" : "2010-11-08T20:11:58Z", "from" : { "type" : "user", "id" : "msscha", "name" : "Mickey Schafer" } }, { "date" : "2010-11-08T18:10:33Z", "from" : { "type" : "user", "id" : "hirosheridan", "name" : "Andrew Lang" } }, { "date" : "2010-11-08T15:21:27Z", "from" : { "type" : "user", "id" : "bersenev", "name" : "Alexey" } }, { "date" : "2010-11-08T15:01:59Z", "from" : { "type" : "user", "id" : "billhooker", "name" : "Bill Hooker" } }, { "date" : "2010-11-08T14:56:21Z", "from" : { "type" : "user", "id" : "sjcockell", "name" : "Simon Cockell" } }, { "date" : "2010-11-08T14:50:05Z", "from" : { "type" : "user", "id" : "lenhat", "private" : true, "name" : "len hat" } }, { "date" : "2010-11-08T14:48:58Z", "from" : { "type" : "user", "id" : "mndoci", "name" : "Deepak Singh" } }, { "date" : "2010-11-08T14:44:00Z", "from" : { "type" : "user", "id" : "kendrak", "private" : true, "name" : "kendrak" } }, { "date" : "2010-11-08T14:40:30Z", "from" : { "type" : "user", "id" : "jcbradley", "name" : "Jean-Claude Bradley" } }, { "date" : "2010-11-08T14:14:21Z", "from" : { "type" : "user", "id" : "gregdurablement", "name" : "GreG Durablement" } }, { "date" : "2010-11-08T13:28:32Z", "from" : { "type" : "user", "id" : "freesci", "name" : "Pawel Szczesny" } }, { "date" : "2010-11-08T10:07:58Z", "from" : { "type" : "user", "id" : "danielmietchen", "name" : "Daniel Mietchen" } }, { "date" : "2010-11-08T09:22:53Z", "from" : { "type" : "user", "id" : "cameronneylon", "name" : "Cameron Neylon" } }, { "date" : "2010-11-08T03:58:10Z", "from" : { "type" : "user", "id" : "suelibrarian", "private" : true, "name" : "suelibrarian" } }, { "date" : "2010-11-08T03:36:06Z", "from" : { "type" : "user", "id" : "mrgunn", "name" : "Mr. Gunn" } } ], "date" : "2010-11-08T03:22:56Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/3810852d2879418eb300a6765cd9da23", "body" : "Seems OpenWetWare is down again. One reason I started hosting my notebook myself, but all of last year's entries still on OWW and it remains very useful! hope it's back up soon(?)", "from" : { "type" : "user", "id" : "cboettig", "name" : "Carl Boettiger" }, "url" : "http://friendfeed.com/oww/3810852d/seems-openwetware-is-down-again-one-reason-i", "to" : [ { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "date" : "2010-12-24T10:49:19Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" },{ "_id" : "e/0a3fdf4c87fa488f85717c16a581f7f8", "body" : "Fwd: Yep, open science works! My open dissertation outlines how to make a gliding motility assay using kinesin and microtubules. It took me nearly a year to perfect the procedure. It took a fellow graduate student at UCSC only two weeks to reproduce my procedures from my open dissertation and get the assay to work. Which, is not trivial and not...", "from" : { "type" : "user", "id" : "pfanderson", "name" : "Patricia F. Anderson" }, "url" : "http://friendfeed.com/opensci-info/0a3fdf4c/fwd-yep-open-science-works-my-dissertation", "to" : [ { "type" : "user", "id" : "pfanderson", "name" : "Patricia's feed" }, { "type" : "group", "id" : "opensci-info", "name" : "Open Science Info" }, { "type" : "group", "name" : "OpenWetWare", "id" : "oww" } ], "likes" : [ { "date" : "2011-02-28T21:13:43Z", "from" : { "type" : "user", "id" : "waterbetta", "private" : true, "name" : "Elisabetta Lambertini" } }, { "date" : "2011-02-28T14:01:54Z", "from" : { "type" : "user", "id" : "serifsiz", "private" : true, "name" : "feraye" } } ], "date" : "2011-02-28T14:01:19Z", "feed_id" : "oww", "feed_name" : "OpenWetWare", "feed_description" : "Share your science", "feed_type" : "group" }] 2 | --------------------------------------------------------------------------------